home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / Macros1.p < prev    next >
Encoding:
Text File  |  1995-10-12  |  121.2 KB  |  5,599 lines  |  [TEXT/PJMM]

  1. unit Macros1;
  2. {Contains the recursive descent parser/interpreter}
  3. {for NIH Image's Pascal-like macro language.}
  4.  
  5. {References:}
  6. {  "Pascal User Manual and Report", Kathleen Jensen and Niklaus Wirth, Springer-Verlag}
  7. {  "Building Your Own C Interpreter", Dr. Dobb's Journal, August 1989}
  8.  
  9. interface
  10.  
  11.     uses
  12.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils,Resources, Errors, Palettes, ColorPicker, Globals, Utilities, RealUtils, Graphics, Edit, {}
  13.         Analysis, Camera, File1, File2, Filters, Macros2, Stacks, Lut, Background, {}
  14.         User, Devices, Serial, PlugIns, Text, projection, math, fft; {,UMacroDef, UMacroRun}
  15.  
  16.  
  17.     procedure RunMacro (nMacro: integer);
  18.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  19.     procedure CloseSerialPorts;
  20.  
  21.  
  22. implementation
  23.  
  24.     const
  25.         EndExpected = '"end" or ";" expected';
  26.         ThenExpected = '"then" expected';
  27.         DivideByZero = 'Divide by zero';
  28.         DoExpected = '"do" expected';
  29.         UntilExpected = '"until" expected';
  30.         RightParenExpected = '")" expected';
  31.         NoImageOpen = 'No Image open';
  32.         MaxArgs = 25;
  33.         MaxLoopCount = 20;
  34.         
  35.     var
  36.         nSaves, ErrorPC, LineStartPC: integer;
  37.         SaveBackground: integer;
  38.         SavePicWidth, SavePicHeight: LongInt;
  39.         SaveMethod: rsMethodType;
  40.         SaveCreate, SaveInvertY, SaveScaleArithmetic, SaveScaleConvolutions: boolean;
  41.         SaveCurrentFontID, SaveCurrentSize, SaveTextJust: integer;
  42.         SaveCurrentStyle: Style;
  43.         SaveTextBack: TextBackType;
  44.         SaveAngle, SaveH, SaveV: extended;
  45.         DoOption, MacroOpPending, StringsAllocated, InPhotoMode: boolean;
  46.         RoutinesCalled: set of CommandType;
  47.         MacroTicks: LongInt;
  48.         LoopCounter: LongInt;
  49.     
  50.  
  51.  
  52.     procedure test;
  53.     var
  54.       op:TokenTypeX;
  55.     begin
  56.         op:=token;
  57.     end;
  58.  
  59.  
  60.     function GetExpression: extended;
  61.     forward;
  62.     function GetBooleanExpression: extended;
  63.     forward;
  64.     procedure DoStatement;
  65.     forward;
  66.     procedure SkipStatement;
  67.     forward;
  68.     procedure DoFor;
  69.     forward;
  70.     procedure MacroError (str: str255);
  71.     forward;
  72.     function GetString: str255;
  73.     forward;
  74.     function GetInteger: LongInt;
  75.     forward;
  76.     procedure SkipIf;
  77.     forward;
  78.     procedure SkipPartialStatement;
  79.     forward;
  80.  
  81.  
  82. {$S MacroUtil}
  83. {Routines from here to the $S compiler directive go in the MacroUtil segment}
  84.  
  85.  
  86.     
  87.     
  88.     procedure PutTokenBack;
  89.     begin
  90.         if token <> DoneT then begin
  91.                 pc := SavePC;
  92.                 token := SaveToken;
  93.             end;
  94.     end;
  95.  
  96.  
  97.     procedure DeallocateStrings (first, last: integer);
  98.         var
  99.             i: integer;
  100.     begin
  101.         with MacrosP^ do begin
  102.                 for i := first to last do begin
  103.                         if Stack[i].StringH <> nil then begin
  104.                                 DisposeHandle(handle(Stack[i].StringH));
  105.                                 Stack[i].StringH := nil;
  106.                             end;
  107.                     end;
  108.             end;
  109.     end;
  110.  
  111.  
  112.     procedure TrimString (var str: str255);
  113.     begin
  114.         if length(str) > 0 then begin
  115.                 while (length(str) > 1) and (str[1] = ' ') do
  116.                     delete(str, 1, 1);
  117.                 while (length(str) > 1) and ((str[length(str)] = ' ') or (str[length(str)] = ';')) do
  118.                     delete(str, length(str), 1);
  119.             end;
  120.     end;
  121.  
  122.  
  123.     procedure LookupVariable;
  124.         var
  125.             VarFound: boolean;
  126.             i: integer;
  127.     begin
  128.         with MacrosP^ do begin
  129.                 VarFound := false;
  130.                 i := TopOfStack + 1;
  131.                 repeat
  132.                     i := i - 1;
  133.                     VarFound := SymbolTableLoc = Stack[i].SymbolTableIndex
  134.                 until VarFound or (i = 1);
  135.                 if VarFound then
  136.                     with stack[i] do begin
  137.                             TokenValue := value;
  138.                             if vType <> StringVar then
  139.                                 token := Variable
  140.                             else begin
  141.                                     token := StringVariable;
  142.                                     if StringH <> nil then
  143.                                         TokenStr := StringH^^
  144.                                     else
  145.                                         TokenStr := 'Deallocated String';
  146.                                 end;
  147.                             TokenStackLoc := i;
  148.                         end;
  149.             end; {with}
  150.     end;
  151.  
  152.  
  153.     function FetchInteger: integer;
  154.         var
  155.             temp: integer;
  156.     begin
  157.         with macrosP^ do begin
  158.                 temp := ord(macros[pc]);
  159.                 pc := pc + 1;
  160.                 FetchInteger := bor(bsl(temp, 8),  ord(macros[pc]));
  161.                 pc := pc + 1;
  162.             end;
  163.     end;
  164.  
  165.  
  166.     procedure LookupProcedure;
  167.     begin
  168.         with MacrosP^ do begin
  169.                 SymbolTableLoc := FetchInteger;
  170.                 with SymbolTable[SymbolTableLoc] do begin
  171.                         TokenLoc := loc;
  172.                         TokenSymbol := symbol;
  173.                     end;
  174.             end;
  175.     end;
  176.  
  177.  
  178.     function FetchReal: real;
  179.         type
  180.             bytes=packed array[1..4] of char;
  181.         var
  182.             vrec:record
  183.                 case integer of
  184.                     1: (rv: real);
  185.                     2: (b: bytes)
  186.                 end;
  187.     begin
  188.         with macrosP^,vrec do begin
  189.             b[1] := macros[pc];
  190.             pc := pc + 1;
  191.             b[2] := macros[pc];
  192.             pc := pc + 1;
  193.             b[3] := macros[pc];
  194.             pc := pc + 1;
  195.             b[4] := macros[pc];
  196.             pc := pc + 1;
  197.             FetchReal:=rv;
  198.         end;
  199.     end;
  200.  
  201.  
  202.     procedure GetToken;
  203.     begin
  204.         with MacrosP^ do begin
  205.                 if token = DoneT then
  206.                     exit(GetToken);
  207.                 SavePC := PC;
  208.                 SaveToken := token;
  209.                 token := TokenTypeX(ord(macros[pc]));
  210.                 while token = NewLineT do begin
  211.                         MacroLineNumber := MacroLineNumber + 1;
  212.                         pc := pc + 1;
  213.                         LineStartPC := pc;
  214.                         if pc > EndMacros then begin
  215.                                 Token := DoneT;
  216.                                 exit(GetToken);
  217.                             end;
  218.                         SavePC := PC;
  219.                         SaveToken := token;
  220.                         token := TokenTypeX(band(ord(macros[pc]),255));
  221.                     end;
  222.                 pc := pc + 1;
  223.                 if pc > EndMacros then begin
  224.                         Token := DoneT;
  225.                         exit(GetToken);
  226.                     end;
  227.                 case token of
  228.                     CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT:
  229.                         begin
  230.                             MacroCommand := CommandType(ord(macros[pc]));
  231.                             pc := pc + 1;
  232.                         end;
  233.                     Identifier:  begin
  234.                             SymbolTableLoc := FetchInteger;
  235.                             if TopOfStack > 0 then
  236.                                 LookupVariable;
  237.                         end;
  238.                     ProcedureT: 
  239.                         LookupProcedure;
  240.                     NumericLiteral: 
  241.                         TokenValue := FetchReal;
  242.                     StringLiteral:  begin
  243.                             TokenStr := '';
  244.                             while ord(macros[pc]) <> 0 do begin
  245.                                     TokenStr := Concat(TokenStr, macros[pc]);
  246.                                     pc := pc + 1;
  247.                                 end;
  248.                             pc := pc + 1;
  249.                         end;
  250.                 end; {case}
  251.             end; {with}
  252.     end;
  253.  
  254.  
  255.     procedure GetMacroName;
  256.         var
  257.             i, len: integer;
  258.     begin
  259.         with MacrosP^ do begin
  260.                 pc := PCStart;
  261.                 repeat
  262.                     pc := pc - 1;
  263.                     if pc < 0 then
  264.                         exit(GetMacroName);
  265.                 until macros[pc] = chr(ord(MacroT));
  266.                 GetToken; {MacroT}
  267.                 GetToken; {Macro name}
  268.                 if Token = StringLiteral then begin
  269.                         len := length(TokenStr);
  270.                         if len > SymbolSize then
  271.                             len := SymbolSize;
  272.                         for i := 1 to len do
  273.                             MacroOrProcName[i] := TokenStr[i];
  274.                     end;
  275.             end;
  276.     end;
  277.  
  278.  
  279.     procedure ConvertTokenToString (t: TokenTypeX; var str: str255);
  280.         var
  281.             i, j, len: integer;
  282.     begin
  283.         with MacrosP^ do
  284.             case token of
  285.                 semicolon: 
  286.                     str := ';';
  287.                 comma: 
  288.                     str := ',';
  289.                 colon: 
  290.                     str := ':';
  291.                 LeftParen: 
  292.                     str := '(';
  293.                 RightParen: 
  294.                     str := ')';
  295.                 LeftBracket: 
  296.                     str := '[';
  297.                 RightBracket: 
  298.                     str := ']';
  299.                 PlusOp: 
  300.                     str := '+';
  301.                 MinusOp: 
  302.                     str := '-';
  303.                 MulOp: 
  304.                     str := '*';
  305.                 DivOp: 
  306.                     str := '/';
  307.                 eqOp: 
  308.                     str := '=';
  309.                 ltOp: 
  310.                     str := '<';
  311.                 gtOp: 
  312.                     str := '>';
  313.                 neOp: 
  314.                     str := '<>';
  315.                 leOp: 
  316.                     str := '<=';
  317.                 geOp: 
  318.                     str := '>=';
  319.                 orOp: 
  320.                     str := 'or';
  321.                 IntDivOp: 
  322.                     str := 'div';
  323.                 modOp: 
  324.                     str := 'mod';
  325.                 andOp: 
  326.                     str := 'and';
  327.                 NotOp: 
  328.                     str := 'not';
  329.                 AssignOp: 
  330.                     str := ':=';
  331.                 Identifier, Variable, StringVariable, ProcIdT:  begin
  332.                         for i := 1 to SymbolSize do
  333.                             str := Concat(str, SymbolTable[SymbolTableLoc].symbol[i]);
  334.                         TrimString(str);
  335.                     end;
  336.                 NumericLiteral:  begin
  337.                         if trunc(TokenValue) = TokenValue then
  338.                             RealToString(TokenValue, 1, 0, str)
  339.                         else
  340.                             RealToString(TokenValue, 1, 1, str);
  341.                     end;
  342.                 StringLiteral: 
  343.                     str := concat('''', TokenStr, '''');
  344.                 CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT: 
  345.                     for i := 1 to nSymbols do begin
  346.                             with SymbolTable[i] do
  347.                                 if (tType = token) and (MacroCommand = cType) then begin
  348.                                         for j := 1 to SymbolSize do
  349.                                             str := Concat(str, symbol[j]);
  350.                                         TrimString(str);
  351.                                     end;
  352.                         end; {for}
  353.                 otherwise
  354.                     for i := 1 to nSymbols do begin
  355.                             with SymbolTable[i] do
  356.                                 if tType = token then begin
  357.                                         for j := 1 to SymbolSize do
  358.                                             str := Concat(str, symbol[j]);
  359.                                         TrimString(str);
  360.                                     end;
  361.                         end; {for}
  362.             end; {case}
  363.     end;
  364.  
  365.  
  366.     procedure GetErrorLine (var ErrorLine: str255);
  367.         var
  368.             str: str255;
  369.     begin
  370.         with MacrosP^ do begin
  371.                 pc := LineStartPC;
  372.                 ErrorLine := '';
  373.                 repeat
  374.                     str := '';
  375.                     if ord(macros[pc]) = ord(NewLineT) then {ppc-bug}
  376.                         leave;
  377.                     GetToken;
  378.                     ConvertTokenToString(token, str);
  379.                     if SavePC = ErrorPC then
  380.                         str := concat('«', str, '»');
  381.                     ErrorLine := concat(ErrorLine, ' ', str);
  382.                 until token = DoneT;
  383.             end;
  384.     end;
  385.  
  386.  
  387.     procedure GetLocalLineNumber;
  388.     begin
  389.         pc := PCStart;
  390.         MacroLineNumber := 1;
  391.         while (pc <= errorpc) and (token <> DoneT) do
  392.             GetToken;
  393.     end;
  394.  
  395.  
  396.     procedure GetGlobalLineNumber;
  397.     begin
  398.         pc := 0;
  399.         MacroLineNumber := 1;
  400.         while (pc <= errorpc) and (token <> DoneT) do
  401.             GetToken;
  402.     end;
  403.     
  404.  
  405.     procedure MacroError (str: str255);
  406.   {Report run-time errors}
  407.         var
  408.             name, ErrorLine, Line: str255;
  409.             i, count, ignore: integer;
  410.     begin
  411.         with MacrosP^ do begin
  412.                 if token = DoneT then
  413.                     exit(MacroError);
  414.                 if TopOfStack > 0 then
  415.                     DeAllocateStrings(nGlobals + 1, TopOfStack);
  416.                 ErrorPC := SavePC;
  417.                 if MacroOrProcName = BlankSymbol then
  418.                     GetMacroName;
  419.                 if MacroOrProcName[SymbolSize] <> ' ' then
  420.                     MacroOrProcName[SymbolSize] := '…';
  421.                 name:='123456789012';
  422.                 for i:=1 to 12 do name[i]:=MacroOrProcName[i];
  423.                 TrimString(name);
  424.                 GetLocalLineNumber;
  425.                 Line := StringOf(MacroLineNumber:1);
  426.                 GetErrorLine(ErrorLine);
  427.                 InitCursor;
  428.                 GetGlobalLineNumber;
  429.                 Line:=StringOf(Line,' (',MacroLineNumber:1,')');
  430.                 ParamText(str, Line, Name, ErrorLine);
  431.                 Ignore := Alert(900, nil);
  432.                 Token := DoneT;
  433.             end; {with}
  434.     end;
  435.  
  436.  
  437.     procedure DoDeclaration;
  438.         var
  439.             SaveStackLoc, StackLoc: integer;
  440.     begin
  441.         SaveStackLoc := TopOfStack;
  442.         while (token = Identifier) or (token = variable) or (token = comma) or (token = StringVariable) do begin
  443.                 if token = StringVariable then begin
  444.                         MacroError('Variable previously defined');
  445.                         exit(DoDeclaration);
  446.                     end;
  447.                 if TopOfStack >= MaxMacroStackSize then begin
  448.                         MacroError(StackOverflow);
  449.                         exit(DoDeclaration);
  450.                     end;
  451.                 TopOfStack := TopOfStack + 1;
  452.                 with MacrosP^.stack[TopOfStack] do begin
  453.                         SymbolTableIndex := SymbolTableLoc;
  454.                         value := 0.0;
  455.                         StringH := nil;
  456.                     end;
  457.                 GetToken;
  458.                 if token = comma then
  459.                     GetToken;
  460.             end; {while}
  461.         if (token = FunctionT) or (token = StringFunctionT) or (token = CommandT) or (token = ArrayT) then
  462.             MacroError('Predefined identifier');
  463.         if token <> colon then
  464.             MacroError('":" expected');
  465.         GetToken;
  466.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) and (token <> StringT) then
  467.             MacroError('"integer", "real", "boolean" or "string" expected');
  468.         for StackLoc := SaveStackLoc + 1 to TopOfStack do
  469.             with macrosP^.stack[StackLoc] do
  470.                 case token of
  471.                     IntegerT: 
  472.                         vType := IntVar;
  473.                     RealT: 
  474.                         vType := RealVar;
  475.                     BooleanT: 
  476.                         vType := BooleanVar;
  477.                     StringT:  begin
  478.                             StringsAllocated := true;
  479.                             vType := StringVar;
  480.                             StringH := str255H(NewHandle(SizeOf(str255)));
  481.                             if StringH = nil then begin
  482.                                     MacroError('Out of memory');
  483.                                     Token := DoneT
  484.                                 end
  485.                             else
  486.                                 StringH^^ := 'Local String';
  487.                         end;
  488.                     otherwise
  489.                 end;
  490.         GetToken;
  491.         if Token = SemiColon then
  492.             GetToken;
  493.     end;
  494.  
  495.  
  496.     procedure GetLeftParen;
  497.     begin
  498.         GetToken;
  499.         if token <> LeftParen then
  500.             MacroError('"(" expected');
  501.     end;
  502.  
  503.  
  504.     procedure GetRightParen;
  505.     begin
  506.         GetToken;
  507.         if token <> RightParen then
  508.             MacroError(RightParenExpected);
  509.     end;
  510.  
  511.  
  512.     procedure GetComma;
  513.     begin
  514.         GetToken;
  515.         if token <> comma then
  516.             MacroError('"," expected');
  517.     end;
  518.  
  519.  
  520.     procedure GetArguments (var str: str255);
  521.         var
  522.             width, fwidth: integer;
  523.             i: LongInt;
  524.             isExpression, ZeroFill, noArgs, notFormatted: boolean;
  525.             n: extended;
  526.             str2: str255;
  527.     begin
  528.         if MacroCommand = WritelnC then begin {Check for Writeln with no arguments}
  529.                 GetToken;
  530.                 noArgs := token <> LeftParen;
  531.                 PutTokenBack;
  532.                 if NoArgs then begin
  533.                         str := '';
  534.                         exit(GetArguments);
  535.                     end;
  536.             end;
  537.         ZeroFill := not (MacroCommand in [DrawTextC, WriteC, WritelnC, PutMsgC, ShowMsgC, PutSerialC, ConcatC]);
  538.         width := 4;
  539.         fwidth := 0;
  540.         str := '';
  541.         GetLeftParen;
  542.         GetToken;
  543.         repeat
  544.             isExpression := token in [Variable, NumericLiteral, FunctionT, UserFuncT, TrueT, FalseT, ArrayT, MinusOp, LeftParen];
  545.             notFormatted := true;
  546.             PutTokenBack;
  547.             if isExpression then
  548.                 n := GetBooleanExpression
  549.             else
  550.                 str2 := GetString;
  551.             GetToken;
  552.             if token = colon then begin
  553.                     notFormatted := false;
  554.                     width := GetInteger;
  555.                     if width < 0 then
  556.                         width := 0;
  557.                     if width > 100 then
  558.                         width := 100;
  559.                     GetToken;
  560.                     if token = colon then begin
  561.                             fwidth := GetInteger;
  562.                             if fwidth < 0 then
  563.                                 width := 0;
  564.                             if fwidth > 12 then
  565.                                 width := 12;
  566.                             GetToken;
  567.                         end;
  568.                 end;
  569.             if token = comma then
  570.                 GetToken;
  571.             if isExpression then begin
  572.                     if notFormatted then
  573.                         if (trunc(n) <> n) and (not ZeroFill) then begin
  574.                                 width := 1;
  575.                                 fwidth := 4;
  576.                             end;
  577.                     str2:=StringOf(n:width:fwidth);
  578.                     if ZeroFill and (n >= 0) then
  579.                         for i := 1 to width do
  580.                             if str2[i] = ' ' then
  581.                                 str2[i] := '0';
  582.                 end;
  583.             str := concat(str, str2);
  584.         until (token = RightParen) or (token = DoneT);
  585.     end;
  586.  
  587.  
  588.     procedure DoUserToken;
  589.     begin
  590.         MacroError('UMX package not installed');
  591.     end;
  592.  
  593.  
  594.     function DoGetString: str255; {(prompt,default:str255)}
  595.         const
  596.             StringID = 3;
  597.         var
  598.             prompt, default: str255;
  599.             Canceled: boolean;
  600.             mylog: DialogPtr;
  601.             item: integer;
  602.     begin
  603.         GetLeftParen;
  604.         prompt := GetString;
  605.         GetToken;
  606.         if token = Comma then
  607.             default := GetString
  608.         else begin
  609.                 default := '';
  610.                 PutTokenBack
  611.             end;
  612.         GetRightParen;
  613.         if Token <> DoneT then begin
  614.                 InitCursor;
  615.                 ParamText(prompt, '', '', '');
  616.                 mylog := GetNewDialog(170, nil, pointer(-1));
  617.                 SetDString(MyLog, StringID, default);
  618.                 SelectdialogItemText(MyLog, StringID, 0, 32767);
  619.                 OutlineButton(MyLog, ok, 16);
  620.                 repeat
  621.                     ModalDialog(nil, item);
  622.                 until (item = ok) or (item = cancel);
  623.                 if item = ok then
  624.                     DoGetString := GetDString(MyLog, StringID)
  625.                 else begin
  626.                         DoGetString := 'cancel';
  627.                         token := DoneT;
  628.                     end;
  629.                 DisposeDialog(mylog);
  630.             end;
  631.     end;
  632.  
  633.  
  634.     function GetSerial: str255;
  635.         var
  636.             count: LongInt;
  637.             buffer: packed array[1..100] of char;
  638.             err: OSErr;
  639.             c:char;
  640.     begin
  641.         if SerialBufferP = nil then begin
  642.                 MacroError('Serial port not open');
  643.                 exit(GetSerial);
  644.             end;
  645.         Err := SerGetBuf(SerialIn, count);
  646.         if count > 0 then begin
  647.                 count := 1;
  648.             Err := FSRead(SerialIn, count, @buffer);
  649.             c:=buffer[1]; {ppc-bug}
  650.             GetSerial :=c;
  651.             end
  652.         else
  653.             GetSerial := '';
  654.     end;
  655.  
  656.  
  657.     procedure RangeCheck (i: LongInt);
  658.     begin
  659.         if (i < 0) or (i > 255) then
  660.             MacroError('Argument is less than 0 or greater than 255');
  661.     end;
  662.  
  663.  
  664.     function DoChr: str255;
  665.         var
  666.             i: LongInt;
  667.     begin
  668.         GetLeftParen;
  669.         i := GetInteger;
  670.         GetRightParen;
  671.         RangeCheck(i);
  672.         if Token <> DoneT then begin
  673.             DoChr := chr(i);
  674.         end;
  675.     end;
  676.  
  677.  
  678.     function GetWindowTitle: str255;
  679.         var
  680.             wPeek: WindowPeek;
  681.     begin
  682.         wPeek := WindowPeek(FrontWindow);
  683.         if wPeek = nil then begin
  684.                 GetWindowTitle := '';
  685.                 exit(GetWindowTitle);
  686.             end;
  687.         if wPeek^.WindowKind = PicKind then
  688.             GetWindowTitle := Info^.title
  689.         else
  690.             GetWindowTitle := wPeek^.TitleHandle^^;
  691.     end;
  692.  
  693.  
  694.     function DoStringFunction: str255;
  695.         var
  696.             str: str255;
  697.     begin
  698.         case MacroCommand of
  699.             GetStringC: 
  700.                 DoStringFunction := DoGetString;
  701.             ChrC: 
  702.                 DoStringFunction := DoChr;
  703.             GetSerialC: 
  704.                 DoStringFunction := GetSerial;
  705.             ConcatC:  begin
  706.                     GetArguments(str);
  707.                     DoStringFunction := str;
  708.                 end;
  709.             WindowTitleC: 
  710.                 DoStringFunction := GetWindowTitle;
  711.             otherwise
  712.                 MacroError('"GetString ", "GetSerial" or "chr" expected');
  713.         end;
  714.     end;
  715.  
  716.  
  717.     function GetString: str255;
  718.     begin
  719.         GetToken;
  720.         if token = StringFunctionT then
  721.             GetString := DoStringFunction
  722.         else if token = UserStrFuncT then begin
  723.                 DoUserToken; {result in TokenStr}
  724.                 GetString := TokenStr;
  725.             end
  726.         else if (token = StringLiteral) or (token = StringVariable) then
  727.             GetString := TokenStr
  728.         else begin
  729.                 MacroError('String expected');
  730.                 GetString := '';
  731.             end;
  732.     end;
  733.  
  734.  
  735.     function GetInteger: LongInt;
  736.         var
  737.             n: LongInt;
  738.             r: extended;
  739.     begin
  740.         r := GetExpression;
  741.         if token = DoneT then begin
  742.                 GetInteger := 0;
  743.                 exit(GetInteger);
  744.             end;
  745.         GetInteger := round(r);
  746.     end;
  747.  
  748.  
  749.     procedure CheckBoolean (b: extended);
  750.     begin
  751.         if (b <> ord(true)) and (b <> ord(false)) then
  752.             MacroError('Boolean expression expected');
  753.     end;
  754.  
  755.  
  756.     function GetBoolean: boolean;
  757.         var
  758.             value: extended;
  759.     begin
  760.         value := GetBooleanExpression;
  761.         CheckBoolean(value);
  762.         GetBoolean := value = ord(true);
  763.     end;
  764.  
  765.  
  766.     function GetBooleanArg: boolean;
  767.     begin
  768.         GetLeftParen;
  769.         GetBooleanArg := GetBoolean;
  770.         GetRightParen;
  771.     end;
  772.  
  773.  
  774.     function GetStringArg: str255;
  775.     begin
  776.         GetLeftParen;
  777.         GetStringArg := GetString;
  778.         GetRightParen;
  779.     end;
  780.  
  781.  
  782.     procedure DoConvolve;
  783.         var
  784.             err: OSErr;
  785.             f: integer;
  786.             FileFound: boolean;
  787.             fname: str255;
  788.     begin
  789.         fname := GetStringArg;
  790.         if token <> DoneT then begin
  791.                 if (fname = '') and (CurrentWindow = TextKind) then begin
  792.                         ConvolveUsingText;
  793.                         exit(DoConvolve);
  794.                     end;
  795.                 err := fsopen(fname, KernelsRefNum, f);
  796.                 FileFound := err = NoErr;
  797.                 err := fsclose(f);
  798.                 if FileFound then
  799.                     convolve(fname, KernelsRefNum)
  800.                 else
  801.                     convolve('', 0);
  802.             end;
  803.     end;
  804.  
  805.  
  806.     function GetNumber: extended; {(prompt:str255; default:extended; [precision:integer])}
  807.         var
  808.             prompt: str255;
  809.             default, n: extended;
  810.             Canceled, OptionalArgument: boolean;
  811.     begin
  812.         GetLeftParen;
  813.         prompt := GetString;
  814.         GetComma;
  815.         default := GetExpression;
  816.         GetToken;
  817.         OptionalArgument := token <> RightParen;
  818.         PutTokenBack;
  819.         if OptionalArgument then begin
  820.                 GetComma;
  821.                 precision := GetInteger;
  822.                 if precision < 0 then
  823.                     precision := 0;
  824.                 if precision > 5 then
  825.                     precision := 5;
  826.         end else
  827.                 precision := 2;
  828.         GetRightParen;
  829.         n := 0.0;
  830.         if Token <> DoneT then begin
  831.                 n := GetReal(prompt, default, precision, Canceled);
  832.                 if Canceled then begin
  833.                         n := default;
  834.                         token := DoneT;
  835.                     end;
  836.             end;
  837.         GetNumber := n;
  838.     end;
  839.  
  840.  
  841.     function DoGetPixel: extended; {(hloc,vloc:integer)}
  842.         var
  843.             hloc, vloc: LongInt;
  844.     begin
  845.         GetLeftParen;
  846.         hloc := GetInteger;
  847.         GetComma;
  848.         vloc := GetInteger;
  849.         GetRightParen;
  850.         if (Token <> DoneT) and (info <> NoInfo) then
  851.             DoGetPixel := MyGetPixel(hloc, vloc)
  852.         else
  853.             DoGetPixel := 0.0;
  854.     end;
  855.  
  856.  
  857.     function DoFunction (c: CommandType): extended;
  858.         var
  859.             n: extended;
  860.             SaveCommand: CommandType;
  861.     begin
  862.         SaveCommand := MacroCommand;
  863.         GetLeftParen;
  864.         n := GetExpression;
  865.         GetRightParen;
  866.         if Token <> DoneT then
  867.             case SaveCommand of
  868.                 truncC: 
  869.                     DoFunction := trunc(n);
  870.                 roundC: 
  871.                     DoFunction := round(n);
  872.                 oddC: 
  873.                     if odd(trunc(n)) then
  874.                         DoFunction := ord(true)
  875.                     else
  876.                         DoFunction := ord(false);
  877.                 absC: 
  878.                     DoFunction := abs(n);
  879.                 sqrtC: 
  880.                     if n < 0.0 then
  881.                         MacroError('Sqrt Error')
  882.                     else
  883.                         DoFunction := sqrt(n);
  884.                 sqrC: 
  885.                     DoFunction := sqr(n);
  886.                 sinC: 
  887.                     DoFunction := sin(n);
  888.                 cosC: 
  889.                     DoFunction := cos(n);
  890.                 expC: 
  891.                     DoFunction := exp(n);
  892.                 lnC: 
  893.                     if n <= 0.0 then
  894.                         MacroError('Log Error')
  895.                     else
  896.                         DoFunction := ln(n);
  897.                 arctanC: 
  898.                     DoFunction := arctan(n);
  899.             end
  900.         else
  901.             DoFunction := 0.0;
  902.     end;
  903.  
  904.  
  905.     function CalibrateValue: extended;
  906.         var
  907.             i: integer;
  908.     begin
  909.         GetLeftParen;
  910.         i := GetInteger;
  911.         GetRightParen;
  912.         RangeCheck(i);
  913.         if Token <> DoneT then begin
  914.                 CalibrateValue := cvalue[i];
  915.             end;
  916.     end;
  917.  
  918.  
  919.     function DoOrd: extended;
  920.         var
  921.             str: str255;
  922.     begin
  923.         GetLeftParen;
  924.         str := GetString;
  925.         GetRightParen;
  926.         if Token <> DoneT then begin
  927.                 if length(str) >= 1 then
  928.                     DoOrd := ord(str[1])
  929.                 else
  930.                     DoOrd := -1;
  931.             end;
  932.     end;
  933.  
  934.  
  935.     function DoStringToNum: extended;
  936.         var
  937.             str: str255;
  938.             n: extended;
  939.     begin
  940.         GetLeftParen;
  941.         str := GetString;
  942.         GetRightParen;
  943.         if Token <> DoneT then begin
  944.                 n := StringToReal(str);
  945.                 if n = BadReal then
  946.                     DoStringToNum := 0.0
  947.                 else
  948.                     DoStringToNum := n;
  949.             end;
  950.     end;
  951.  
  952.  
  953.     function DoLogicalFunction (c: CommandType): extended;
  954.         var
  955.             n1, n2: LongInt;
  956.     begin
  957.         GetLeftParen;
  958.         n1 := GetInteger;
  959.         GetComma;
  960.         n2 := GetInteger;
  961.         GetRightParen;
  962.         if Token <> DoneT then begin
  963.                 if c = BitAndC then
  964.                     DoLogicalFunction := band(n1, n2)
  965.                 else
  966.                     DoLogicalFunction := bor(n1, n2)
  967.             end;
  968.     end;
  969.  
  970.  
  971.     function PidExists: boolean; {(pid:integer)}
  972.         var
  973.             pid, i: integer;
  974.     begin
  975.         GetLeftParen;
  976.         pid := GetInteger;
  977.         GetRightParen;
  978.         if Token <> DoneT then begin
  979.                 PidExists := false;
  980.                 for i := 1 to nPics do
  981.                     if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = pid then begin
  982.                             PidExists := true;
  983.                             leave;
  984.                         end;
  985.             end;
  986.     end;
  987.  
  988.  
  989.     function DoPos: integer;
  990.         var
  991.             substr, str: str255;
  992.     begin
  993.         GetLeftParen;
  994.         substr := GetString;
  995.         GetComma;
  996.         str := GetString;
  997.         GetRightParen;
  998.         if Token <> DoneT then
  999.             DoPos := pos(substr, str);
  1000.     end;
  1001.  
  1002.  
  1003.     function DoLength: integer;
  1004.         var
  1005.             str: str255;
  1006.     begin
  1007.         GetLeftParen;
  1008.         str := GetString;
  1009.         GetRightParen;
  1010.         if Token <> DoneT then
  1011.             DoLength := length(str);
  1012.     end;
  1013.  
  1014.  
  1015.     function isKeyDown:boolean; {(key:string)}
  1016.         var
  1017.             key: str255;
  1018.     begin
  1019.         GetLeftParen;
  1020.         key := GetString;
  1021.         GetRightParen;
  1022.         if token <> DoneT then begin
  1023.             MakeLowerCase(key);
  1024.             isKeydown:=false;
  1025.             if (pos('option', key) <> 0) and OptionKeyDown then
  1026.                 isKeyDown:=true
  1027.             else if (pos('shift', key) <> 0) and ShiftKeyDown then
  1028.                 isKeyDown:=true
  1029.             else if (pos('control', key) <> 0) and ControlKeyDown then
  1030.                 isKeyDown:=true;
  1031.         end;
  1032.     end;
  1033.  
  1034.  
  1035.     function GetParameter:LongInt; {parameter:string}
  1036.         var
  1037.             param: str255;
  1038.     begin
  1039.         GetLeftParen;
  1040.         param := GetString;
  1041.         GetRightParen;
  1042.         if token <> DoneT then begin
  1043.             MakeLowerCase(param);
  1044.             if pos('maxmeasure', param) <> 0 then
  1045.                 GetParameter := MaxMeasurements
  1046.             else if pos('undo', param) <> 0 then
  1047.                 GetParameter := UndoBufSize
  1048.             else if pos('freemem', param) <> 0 then
  1049.                 GetParameter := FreeMem
  1050.             else if pos('maxblock', param) <> 0 then
  1051.                 GetParameter := MaxBlock
  1052.             else if pos('roitype', param) <> 0 then begin
  1053.                 if info = nil then
  1054.                     GetParameter := 0
  1055.                 else case Info^.RoiType of
  1056.                     noRoi: GetParameter := 0;
  1057.                     RectRoi: GetParameter := 1;
  1058.                     OvalRoi: GetParameter := 2;
  1059.                     PolygonRoi: GetParameter := 3;
  1060.                     FreehandRoi: GetParameter := 4;
  1061.                     TracedRoi: GetParameter := 5;
  1062.                     LineRoi: GetParameter := 6;
  1063.                     FreeLineRoi: GetParameter := 7;
  1064.                     SegLineRoi: GetParameter := 8;
  1065.                 end
  1066.             end else begin
  1067.                 MacroError('Invalid argument');
  1068.                 GetParameter := 0;
  1069.             end;
  1070.         end;
  1071.     end;
  1072.  
  1073.  
  1074.     function ExecuteFunction: extended;
  1075.     begin
  1076.         case MacroCommand of
  1077.             TruncC, RoundC, oddC, absC, sqrtC, sqrC, sinC, cosC, expC, lnC, arctanC: 
  1078.                 ExecuteFunction := DoFunction(MacroCommand);
  1079.             GetNumC: 
  1080.                 ExecuteFunction := GetNumber;
  1081.             RandomC: 
  1082.                 ExecuteFunction := (random + 32767.0) / 65534.0;
  1083.             GetPixelC: 
  1084.                 ExecuteFunction := DoGetPixel;
  1085.             ButtonC:  begin
  1086.                     ExecuteFunction := ord(Button);
  1087.                     FlushEvents(EveryEvent, 0);
  1088.                 end;
  1089.             nPicsC: 
  1090.                 ExecuteFunction := nPics;
  1091.             PicNumC: 
  1092.                 ExecuteFunction := info^.PicNum;
  1093.             PidNumC: 
  1094.                 ExecuteFunction := info^.PidNum;
  1095.             PidExistsC: 
  1096.                 ExecuteFunction := ord(PidExists);
  1097.             SameSizeC: 
  1098.                 ExecuteFunction := ord(AllSameSize);
  1099.             cValueC: 
  1100.                 ExecuteFunction := CalibrateValue;
  1101.             CalibratedC: 
  1102.                 ExecuteFunction := ord(info^.fit <> uncalibrated);
  1103.             rCountC: 
  1104.                 ExecuteFunction := mCount;
  1105.             GetSliceC: 
  1106.                 with info^ do
  1107.                     if StackInfo = nil then
  1108.                         ExecuteFunction := 0
  1109.                     else
  1110.                         ExecuteFunction := Info^.StackInfo^.CurrentSlice;
  1111.             nSlicesC: 
  1112.                 with info^ do
  1113.                     if StackInfo = nil then
  1114.                         ExecuteFunction := 0
  1115.                     else
  1116.                         ExecuteFunction := Info^.StackInfo^.nSlices;
  1117.             GetSpacingC: 
  1118.                 with info^ do
  1119.                     if StackInfo = nil then
  1120.                         MacroError('No stack')
  1121.                     else with Info^.StackInfo^ do begin
  1122.                         if StackType = MovieStack then
  1123.                             ExecuteFunction := Info^.StackInfo^.FrameInterval
  1124.                         else
  1125.                             ExecuteFunction := Info^.StackInfo^.SliceSpacing;
  1126.                     end;
  1127.             nCoordinatesC: 
  1128.                 ExecuteFunction := nCoordinates;
  1129.             OrdC: 
  1130.                 ExecuteFunction := DoOrd;
  1131.             TickCountC: 
  1132.                 ExecuteFunction := TickCount;
  1133.             StringToNumC: 
  1134.                 ExecuteFunction := DoStringToNum;
  1135.             UndoSizeC: 
  1136.                 ExecuteFunction := UndoBufSize;
  1137.             BitAndC, BitOrC: 
  1138.                 ExecuteFunction := DoLogicalFunction(MacroCommand);
  1139.             PosC: 
  1140.                 ExecuteFunction := DoPos;
  1141.             LengthC: 
  1142.                 ExecuteFunction := DoLength;
  1143.             KeyDownC:
  1144.                 ExecuteFunction := ord(isKeyDown);
  1145.             GetC:
  1146.                 ExecuteFunction := GetParameter;
  1147.         end; {case}
  1148.     end;
  1149.  
  1150.  
  1151.     procedure CheckIndex (index, min, max: LongInt);
  1152.     begin
  1153.         if (index < min) or (index > max) then
  1154.             MacroError('Array index out of range');
  1155.     end;
  1156.  
  1157.  
  1158.     function GetArrayValue: extended;
  1159.         var
  1160.             SaveArrayType: ArrayType;
  1161.             Index: LongInt;
  1162.             xcoord, ycoord: integer;
  1163.     begin
  1164.         SaveArrayType := ArrayType(MacroCommand);
  1165.         GetToken;
  1166.         if token <> LeftBracket then
  1167.             MacroError('"[" expected');
  1168.         Index := GetInteger;
  1169.         GetToken;
  1170.         if token <> RightBracket then
  1171.             MacroError('"]" expected');
  1172.         case SaveArrayType of
  1173.             HistogramA:  begin
  1174.                     RangeCheck(Index);
  1175.                     GetArrayValue := histogram[Index];
  1176.                 end;
  1177.             rAreaA:  begin
  1178.                     CheckIndex(Index, 1, MaxMeasurements);
  1179.                     GetArrayValue := mArea^[Index];
  1180.                 end;
  1181.             rMeanA:  begin
  1182.                     CheckIndex(Index, 1, MaxMeasurements);
  1183.                     GetArrayValue := mean^[Index];
  1184.                 end;
  1185.             rStdDevA:  begin
  1186.                     CheckIndex(Index, 1, MaxMeasurements);
  1187.                     GetArrayValue := sd^[Index];
  1188.                 end;
  1189.             rXA:  begin
  1190.                     CheckIndex(Index, 1, MaxMeasurements);
  1191.                     GetArrayValue := xcenter^[Index];
  1192.                 end;
  1193.             rYA:  begin
  1194.                     CheckIndex(Index, 1, MaxMeasurements);
  1195.                     GetArrayValue := ycenter^[Index];
  1196.                 end;
  1197.             rLengthA:  begin
  1198.                     CheckIndex(Index, 1, MaxMeasurements);
  1199.                     GetArrayValue := pLength^[Index];
  1200.                 end;
  1201.             rMinA:  begin
  1202.                     CheckIndex(Index, 1, MaxMeasurements);
  1203.                     GetArrayValue := mMin^[Index];
  1204.                 end;
  1205.             rMaxA:  begin
  1206.                     CheckIndex(Index, 1, MaxMeasurements);
  1207.                     GetArrayValue := mMax^[Index];
  1208.                 end;
  1209.             rMajorA:  begin
  1210.                     CheckIndex(Index, 1, MaxMeasurements);
  1211.                     GetArrayValue := MajorAxis^[Index];
  1212.                 end;
  1213.             rMinorA:  begin
  1214.                     CheckIndex(Index, 1, MaxMeasurements);
  1215.                     GetArrayValue := MinorAxis^[Index];
  1216.                 end;
  1217.             rAngleA:  begin
  1218.                     CheckIndex(Index, 1, MaxMeasurements);
  1219.                     GetArrayValue := orientation^[Index];
  1220.                 end;
  1221.             rUser1A:  begin
  1222.                     CheckIndex(Index, 1, MaxMeasurements);
  1223.                     GetArrayValue := User1^[Index];
  1224.                 end;
  1225.             rUser2A:  begin
  1226.                     CheckIndex(Index, 1, MaxMeasurements);
  1227.                     GetArrayValue := User2^[Index];
  1228.                 end;
  1229.             RedLutA, GreenLutA, BlueLutA: 
  1230.                 if OptionKeyDown then begin
  1231.                         RangeCheck(Index);
  1232.                         if Token <> DoneT then
  1233.                             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb do
  1234.                                 case SaveArrayType of
  1235.                                     RedLutA: 
  1236.                                         GetArrayValue := band(bsr(red, 8), 255);
  1237.                                     GreenLutA: 
  1238.                                         GetArrayValue := band(bsr(green, 8), 255);
  1239.                                     BlueLutA: 
  1240.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1241.                                 end; {case}
  1242.                     end
  1243.                 else begin
  1244.                         RangeCheck(Index);
  1245.                         if Token <> DoneT then
  1246.                             with osGDevice^^.gdPMap^^.pmTable^^.ctTable[index].rgb do
  1247.                                 case SaveArrayType of
  1248.                                     RedLutA: 
  1249.                                         GetArrayValue := band(bsr(red, 8), 255);
  1250.                                     GreenLutA: 
  1251.                                         GetArrayValue := band(bsr(green, 8), 255);
  1252.                                     BlueLutA: 
  1253.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1254.                                 end; {case}
  1255.                     end;
  1256.             BufferA:  begin
  1257.                     CheckIndex(Index, 0, MaxLine - 1);
  1258.                     if Token <> DoneT then
  1259.                         GetArrayValue := MacrosP^.aLine[index];
  1260.                 end;
  1261.             PlotDataA:  begin
  1262.                     CheckIndex(Index, 0, MaxLine - 1);
  1263.                     if Token <> DoneT then
  1264.                         GetArrayValue := PlotData^[index];
  1265.                 end;
  1266.             xCoordinatesA:  begin
  1267.                     CheckIndex(Index, 1, MaxCoordinates);
  1268.                     if Token <> DoneT then
  1269.                         with info^ do begin
  1270.                                 xcoord := xCoordinates^[index];
  1271.                                 if SpatiallyCalibrated then
  1272.                                     GetArrayValue := xcoord / xScale
  1273.                                 else
  1274.                                     GetArrayValue := xcoord
  1275.                             end;
  1276.                 end;
  1277.             yCoordinatesA:  begin
  1278.                     CheckIndex(Index, 1, MaxCoordinates);
  1279.                     if Token <> DoneT then
  1280.                         with info^ do begin
  1281.                                 ycoord := yCoordinates^[index];
  1282.                                 if InvertYCoordinates and (Info <> NoInfo) then
  1283.                                     ycoord := Info^.PicRect.bottom - ycoord - 1;
  1284.                                 if SpatiallyCalibrated then
  1285.                                     GetArrayValue := ycoord / yScale
  1286.                                 else
  1287.                                     GetArrayValue := ycoord
  1288.                             end;
  1289.                 end;
  1290.             ScionA:  begin
  1291.                     if framegrabber <> ScionLG3 then
  1292.                         MacroError('No Scion LG-3');
  1293.                     if Token <> DoneT then
  1294.                         CheckIndex(Index, 1, 4);
  1295.                     if Token <> DoneT then
  1296.                         case index of
  1297.                             1: 
  1298.                                 GetArrayValue := LG3DacA;
  1299.                             2: 
  1300.                                 GetArrayValue := LG3DacB;
  1301.                             3: 
  1302.                                 GetArrayValue := ControlReg^;
  1303.                             4: 
  1304.                                 GetArrayValue := LG3DataOut;
  1305.                         end;
  1306.                 end;
  1307.         end; {case}
  1308.     end;
  1309.  
  1310.  
  1311.     function GetStringValue: extended;
  1312.  {Convert string to a base 102 number so we can do comparisons.}
  1313.         const
  1314.             base = 102;
  1315.         var
  1316.             i, j: integer;
  1317.             v, k: extended;
  1318.     begin
  1319.         MakeLowerCase(TokenStr);
  1320.         k := 1;
  1321.         v := 0.0;
  1322.         for i := 1 to length(TokenStr) do begin
  1323.                 j := ord(TokenStr[i]);
  1324.                 if j > 127 then
  1325.                     j := 127;
  1326.                 if j >= 91 then
  1327.                     j := j - 26;
  1328.                 v := v + j * k;
  1329.                 k := k * base;
  1330.             end;
  1331.         GetStringValue := v;
  1332.     end;
  1333.  
  1334.  
  1335.     function GetValue: extended;
  1336.     begin
  1337.         case token of
  1338.             Variable, NumericLiteral: 
  1339.                 GetValue := TokenValue;
  1340.             FunctionT: 
  1341.                 GetValue := ExecuteFunction;
  1342.             StringFunctionT:  begin
  1343.                     TokenStr := DoStringFunction;
  1344.                     GetValue := GetStringValue;
  1345.                 end;
  1346.             UserFuncT:  begin
  1347.                     DoUserToken;{output in TokenValue}
  1348.                     GetValue := TokenValue;
  1349.                 end;
  1350.             UserStrFuncT:  begin
  1351.                     DoUserToken; {output in TokenStr}
  1352.                     GetValue := GetStringValue;
  1353.                 end;
  1354.             TrueT: 
  1355.                 GetValue := ord(true);
  1356.             FalseT: 
  1357.                 GetValue := ord(false);
  1358.             ArrayT: 
  1359.                 GetValue := GetArrayValue;
  1360.             StringVariable, StringLiteral: 
  1361.                 GetValue := GetStringValue;
  1362.             otherwise begin
  1363.                     MacroError('Number expected');
  1364.                     GetValue := 0.0;
  1365.                     exit(GetValue);
  1366.                 end;
  1367.         end; {case}
  1368.     end;
  1369.  
  1370.  
  1371.     function GetFactor: extended;
  1372.         var
  1373.             fValue: extended;
  1374.             isUnaryMinus, isNot: boolean;
  1375.     begin
  1376.         GetToken;
  1377.         isUnaryMinus := token = MinusOp;
  1378.         isNot := token = NotOp;
  1379.         if isUnaryMinus or isNot then
  1380.             GetToken;
  1381.         case token of
  1382.             Variable, NumericLiteral, FunctionT, StringFunctionT, UserFuncT, 
  1383.             UserStrFuncT, TrueT, FalseT, ArrayT, StringVariable, StringLiteral: 
  1384.                 fValue := GetValue;
  1385.             LeftParen:  begin
  1386.                     fValue := GetBooleanExpression;
  1387.                     GetRightParen;
  1388.                 end;
  1389.             otherwise begin
  1390.                     macroError('Undefined identifier');
  1391.                     fvalue := 0.0
  1392.                 end;
  1393.         end;
  1394.         if isUnaryMinus then
  1395.             fValue := -fValue;
  1396.         if isNot then
  1397.             if fValue = ord(true) then
  1398.                 fValue := ord(false)
  1399.             else
  1400.                 fValue := ord(true);
  1401.         GetFactor := fValue;
  1402.         GetToken;
  1403.     end;
  1404.  
  1405.  
  1406.     function GetTerm: extended;
  1407.         var
  1408.             tValue, fValue: extended;
  1409.             op: TokenTypeX;
  1410.     begin
  1411.         tValue := GetFactor;
  1412.         while token in [MulOp, IntDivOp, ModOp, DivOp, AndOp] do begin
  1413.                 op := token;
  1414.                 fValue := GetFactor;
  1415.                 case op of
  1416.                     MulOp: 
  1417.                         tValue := tValue * fValue;
  1418.                     IntDivOp: 
  1419.                         if fValue <> 0.0 then
  1420.                             tValue := trunc(tValue) div trunc(fValue)
  1421.                         else
  1422.                             MacroError(DivideByZero);
  1423.                     ModOp: 
  1424.                         if fValue <> 0.0 then
  1425.                             tValue := trunc(tValue) mod trunc(fValue)
  1426.                         else
  1427.                             MacroError(DivideByZero);
  1428.                     DivOp: 
  1429.                         if fValue <> 0.0 then
  1430.                             tValue := tValue / fValue
  1431.                         else
  1432.                             MacroError(DivideByZero);
  1433.                     AndOp:  begin
  1434.                             CheckBoolean(tValue);
  1435.                             CheckBoolean(fValue);
  1436.                             tValue := ord((tValue = ord(true)) and (fValue = ord(true)));
  1437.                         end;
  1438.                 end; {case}
  1439.             end; {while}
  1440.         GetTerm := tValue;
  1441.     end;
  1442.  
  1443.  
  1444.     function GetSimpleExpression: extended;
  1445.         var
  1446.             seValue, tValue: extended;
  1447.             op: TokenTypeX;
  1448.     begin
  1449.         seValue := GetTerm;
  1450.         while token in [PlusOp, MinusOp, OrOp] do begin
  1451.                 op := token;
  1452.                 tValue := GetTerm;
  1453.                 case op of
  1454.                     PlusOp: 
  1455.                         seValue := seValue + tValue;
  1456.                     MinusOp: 
  1457.                         seValue := seValue - tValue;
  1458.                     orOp:  begin
  1459.                             CheckBoolean(seValue);
  1460.                             CheckBoolean(tValue);
  1461.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1462.                         end;
  1463.                 end;
  1464.             end;
  1465.         GetSimpleExpression := seValue;
  1466.     end;
  1467.  
  1468.  
  1469.     function GetExpression: extended;
  1470.         var
  1471.             seValue, tValue: extended;
  1472.             op: TokenTypeX;
  1473.     begin
  1474.         seValue := GetTerm;
  1475.         while token in [PlusOp, MinusOp, OrOp] do begin
  1476.                 op := token;
  1477.                 tValue := GetTerm;
  1478.                 case op of
  1479.                     PlusOp: 
  1480.                         seValue := seValue + tValue;
  1481.                     MinusOp: 
  1482.                         seValue := seValue - tValue;
  1483.                     orOp:  begin
  1484.                             CheckBoolean(seValue);
  1485.                             CheckBoolean(tValue);
  1486.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1487.                         end;
  1488.                 end;
  1489.             end;
  1490.         GetExpression := seValue;
  1491.         PutTokenBack;
  1492.     end;
  1493.  
  1494.  
  1495.     function GetBooleanExpression: extended;
  1496.         var
  1497.             eValue, seValue: extended;
  1498.             op: TokenTypeX;
  1499.     begin
  1500.         eValue := GetSimpleExpression;
  1501.         while token in [eqOp, ltOp, gtOp, neOp, leOp, geOp] do begin
  1502.                 op := token;
  1503.                 seValue := GetSimpleExpression;
  1504.                 case op of
  1505.                     eqOp: 
  1506.                         eValue := ord(eValue = seValue);
  1507.                     ltOp: 
  1508.                         eValue := ord(eValue < seValue);
  1509.                     gtOp: 
  1510.                         eValue := ord(eValue > seValue);
  1511.                     neOp: 
  1512.                         eValue := ord(eValue <> seValue);
  1513.                     leOp: 
  1514.                         eValue := ord(eValue <= seValue);
  1515.                     geOp: 
  1516.                         eValue := ord(eValue >= seValue);
  1517.                 end;
  1518.             end;
  1519.         GetBooleanExpression := eValue;
  1520.         PutTokenBack;
  1521.     end;
  1522.  
  1523.  
  1524. {$S}
  1525. {Routines from here to the end of the file go in the macro1 segment}
  1526.  
  1527.     procedure DoCapture;
  1528.     begin
  1529.         CaptureAndDisplayFrame;
  1530.         if ContinuousHistogram then
  1531.             ShowContinuousHistogram;
  1532.     end;
  1533.  
  1534.  
  1535.     procedure DoWait;
  1536.         var
  1537.             seconds: extended;
  1538.             SaveTicks: LongInt;
  1539.             str: str255;
  1540.             theEvent: EventRecord;
  1541.     begin
  1542.         GetLeftParen;
  1543.         seconds := GetExpression;
  1544.         GetRightParen;
  1545.         if Token <> DoneT then begin
  1546.                 SaveTicks := TickCount + round(seconds * 60.0);
  1547.                 repeat
  1548.                     if Digitizing then
  1549.                         DoCapture;
  1550.                     if EventAvail(everyEvent, theEvent) then
  1551.                         ; {Allows background tasks to run}
  1552.                 until (TickCount > SaveTicks) or CommandPeriod;
  1553.             end;
  1554.     end;
  1555.  
  1556.  
  1557.     procedure SetDensitySlice; {LowerLevel,UpperLevel:integer}
  1558.   {Disable density slicing if lower and upper=0 and enable it up lower and upper=255}
  1559.         var
  1560.             sStart, sEnd: integer;
  1561.     begin
  1562.         GetLeftParen;
  1563.         sStart := GetInteger;
  1564.         RangeCheck(sStart);
  1565.         GetComma;
  1566.         sEnd := GetInteger;
  1567.         RangeCheck(sEnd);
  1568.         GetRightParen;
  1569.         if Token <> DoneT then begin
  1570.                 DisableDensitySlice;
  1571.                 DisableThresholding;
  1572.                 if (sEnd < sStart) or ((sStart = 0) and (sEnd = 0)) then
  1573.                     exit(SetDensitySlice);
  1574.                 if not ((sStart = 255) and (sEnd = 255)) then begin
  1575.                         SliceStart := sStart;
  1576.                         SliceEnd := sEnd;
  1577.                         if SliceStart < 1 then
  1578.                             SliceStart := 1;
  1579.                         if SliceEnd > 254 then
  1580.                             SliceEnd := 254;
  1581.                     end;
  1582.                 EnableDensitySlice;
  1583.             end;
  1584.     end;
  1585.  
  1586.  
  1587.     procedure SetColor;
  1588.         var
  1589.             index: integer;
  1590.             SaveCommand: CommandType;
  1591.     begin
  1592.         SaveCommand := MacroCommand;
  1593.         GetLeftParen;
  1594.         index := GetInteger;
  1595.         GetRightParen;
  1596.         RangeCheck(index);
  1597.         if Token <> DoneT then begin
  1598.                 if SaveCommand = SetForeC then
  1599.                     SetForegroundColor(index)
  1600.                 else
  1601.                     SetBackgroundColor(index);
  1602.             end;
  1603.     end;
  1604.  
  1605.  
  1606.     procedure DoConstantArithmetic;
  1607.         var
  1608.             constant: extended;
  1609.             SaveCommand: CommandType;
  1610.     begin
  1611.         SaveCommand := MacroCommand;
  1612.         GetLeftParen;
  1613.         constant := GetExpression;
  1614.         GetRightParen;
  1615.         if token <> DoneT then
  1616.             case SaveCommand of
  1617.                 AddConstC: 
  1618.                     DoArithmetic(AddItem, constant);
  1619.                 MulConstC: 
  1620.                     DoArithmetic(MultiplyItem, constant);
  1621.             end;
  1622.     end;
  1623.  
  1624.  
  1625.     procedure GetNextWindow;
  1626.         var
  1627.             n: integer;
  1628.     begin
  1629.         n := info^.PicNum + 1;
  1630.         if n > nPics then
  1631.             n := 1;
  1632.         StopDigitizing;
  1633.         SaveRoi;
  1634.         DisableDensitySlice;
  1635.         SelectWindow(PicWindow[n]);
  1636.         Info := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1637.         ActivateWindow;
  1638.         GenerateValues;
  1639.         LoadLUT(info^.cTable);
  1640.         UpdatePicWindow;
  1641.     end;
  1642.  
  1643.  
  1644.     procedure DoRevert;
  1645.     begin
  1646.         if info^.revertable then begin
  1647.                 RevertToSaved;
  1648.                 UpdatePicWindow;
  1649.             end
  1650.         else
  1651.             MacroError('Unable to revert');
  1652.     end;
  1653.  
  1654.  
  1655.     procedure MakeRoi;
  1656.         var
  1657.             Left, Top, Width, Height: integer;
  1658.             SaveCommand: CommandType;
  1659.     begin
  1660.         SaveCommand := MacroCommand;
  1661.         GetLeftParen;
  1662.         left := GetInteger;
  1663.         GetComma;
  1664.         top := GetInteger;
  1665.         GetComma;
  1666.         width := GetInteger;
  1667.         if width < 1 then
  1668.             width := 1;
  1669.         GetComma;
  1670.         height := GetInteger;
  1671.         if height < 1 then
  1672.             height := 1;
  1673.         GetRightParen;
  1674.         KillRoi;
  1675.         if token <> DoneT then
  1676.             with Info^ do begin
  1677.                     StopDigitizing;
  1678.                     if SaveCommand = MakeOvalC then
  1679.                         RoiType := OvalRoi
  1680.                     else
  1681.                         RoiType := RectRoi;
  1682.                     SetRect(RoiRect, left, top, left + width, top + height);
  1683.                     MakeRegion;
  1684.                     SetupUndo;
  1685.                     RoiShowing := true;
  1686.                 end;
  1687.     end;
  1688.  
  1689.  
  1690.     procedure MoveRoi;
  1691.         var
  1692.             DeltaH, DeltaV: integer;
  1693.     begin
  1694.         GetLeftParen;
  1695.         DeltaH := GetInteger;
  1696.         GetComma;
  1697.         DeltaV := GetInteger;
  1698.         GetRightParen;
  1699.         with info^ do begin
  1700.                 if not RoiShowing then begin
  1701.                         MacroError('No Selection');
  1702.                         exit(MoveRoi);
  1703.                     end;
  1704.                 OffsetRgn(roiRgn, DeltaH, DeltaV);
  1705.                 RoiRect := roiRgn^^.rgnBBox;
  1706.             end;
  1707.     end;
  1708.  
  1709.  
  1710.     procedure InsetRoi;
  1711.         var
  1712.             delta: integer;
  1713.     begin
  1714.         GetLeftParen;
  1715.         delta := GetInteger;
  1716.         GetRightParen;
  1717.         with info^ do begin
  1718.                 if not RoiShowing then begin
  1719.                         MacroError('No Selection');
  1720.                         exit(InsetRoi);
  1721.                     end;
  1722.                 InsetRgn(roiRgn, delta, delta);
  1723.                 RoiRect := roiRgn^^.rgnBBox;
  1724.             end;
  1725.     end;
  1726.  
  1727.  
  1728.     procedure DoMoveTo; {(x,y:integer)}
  1729.     begin
  1730.         GetLeftParen;
  1731.         CurrentX := GetInteger;
  1732.         GetComma;
  1733.         CurrentY := GetInteger;
  1734.         GetRightParen;
  1735.         InsertionPoint.h := CurrentX;
  1736.         InsertionPoint.v := CurrentY + 4;
  1737.     end;
  1738.  
  1739.  
  1740.     procedure DoDrawtext (str: str255; EndOfLine: boolean);
  1741.     begin
  1742.         if info <> NoInfo then begin
  1743.                 KillRoi;
  1744.                 DrawTextString(str, InsertionPoint, TextJust);
  1745.                 if EndOfLine then begin
  1746.                         CurrentY := CurrentY + CurrentSize;
  1747.                         InsertionPoint.h := CurrentX;
  1748.                         InsertionPoint.v := CurrentY + 4;
  1749.                     end;
  1750.             end;
  1751.     end;
  1752.  
  1753.  
  1754.     procedure DrawNumber;
  1755.         var
  1756.             n: extended;
  1757.             str: str255;
  1758.             fwidth: integer;
  1759.     begin
  1760.         GetLeftParen;
  1761.         n := GetExpression;
  1762.         GetRightParen;
  1763.         if token <> DoneT then begin
  1764.                 if n = trunc(n) then
  1765.                     fwidth := 0
  1766.                 else
  1767.                     fwidth := precision;
  1768.                 RealToString(n, 1, fwidth, str);
  1769.                 DoDrawText(str, true);
  1770.             end;
  1771.     end;
  1772.  
  1773.  
  1774.     procedure SetFont;
  1775.         var
  1776.             FontName: str255;
  1777.             id: integer;
  1778.     begin
  1779.         FontName := GetStringArg;
  1780.         if Token <> DoneT then begin
  1781.                 GetFNum(FontName, id);
  1782.                 if id = 0 then
  1783.                     MacroError('Font not available')
  1784.                 else
  1785.                     CurrentFontID := id;
  1786.             end;
  1787.     end;
  1788.  
  1789.  
  1790.     procedure SetFontSize;
  1791.         var
  1792.             size: integer;
  1793.     begin
  1794.         GetLeftParen;
  1795.         Size := GetInteger;
  1796.         GetRightParen;
  1797.         if (size < 6) or (size > 720) then
  1798.             MacroError('Argument out of range');
  1799.         if Token <> DoneT then
  1800.             CurrentSize := size;
  1801.     end;
  1802.  
  1803.  
  1804.     procedure SetText;
  1805.         var
  1806.             Attributes: str255;
  1807.     begin
  1808.         Attributes := GetStringArg;
  1809.         if Token <> DoneT then begin
  1810.                 MakeLowerCase(Attributes);
  1811.                 if pos('with', Attributes) <> 0 then
  1812.                     TextBack := WithBack;
  1813.                 if pos('no', Attributes) <> 0 then
  1814.                     TextBack := NoBack;
  1815.                 if pos('left', Attributes) <> 0 then
  1816.                     TextJust := teJustLeft;
  1817.                 if pos('center', Attributes) <> 0 then
  1818.                     TextJust := teJustCenter;
  1819.                 if pos('right', Attributes) <> 0 then
  1820.                     TextJust := teJustRight;
  1821.                 CurrentStyle := [];
  1822.                 if pos('bold', Attributes) <> 0 then
  1823.                     CurrentStyle := CurrentStyle + [Bold];
  1824.                 if pos('italic', Attributes) <> 0 then
  1825.                     CurrentStyle := CurrentStyle + [Italic];
  1826.                 if pos('underline', Attributes) <> 0 then
  1827.                     CurrentStyle := CurrentStyle + [Underline];
  1828.                 if pos('outline', Attributes) <> 0 then
  1829.                     CurrentStyle := CurrentStyle + [Outline];
  1830.                 if pos('shadow', Attributes) <> 0 then
  1831.                     CurrentStyle := CurrentStyle + [Shadow];
  1832.             end;
  1833.     end;
  1834.  
  1835.  
  1836.     procedure DoPutMessage;
  1837.         var
  1838.             str: str255;
  1839.     begin
  1840.         GetArguments(str);
  1841.         if Token <> DoneT then
  1842.             PutMessage(str)
  1843.     end;
  1844.  
  1845.  
  1846.     function GetVar: integer;
  1847.     begin
  1848.         GetVar := 0;
  1849.         GetToken;
  1850.         if token <> Variable then
  1851.             MacroError('Variable expected')
  1852.         else
  1853.             GetVar := TokenStackLoc;
  1854.     end;
  1855.  
  1856.  
  1857.     procedure GetPicSize;  {(width,height)}
  1858.         var
  1859.             loc1, loc2: integer;
  1860.     begin
  1861.         GetLeftParen;
  1862.         loc1 := GetVar;
  1863.         GetComma;
  1864.         loc2 := GetVar;
  1865.         GetRightParen;
  1866.         if Token <> DoneT then
  1867.             with MacrosP^ do
  1868.                 if info = NoInfo then begin
  1869.                         stack[loc1].value := 0.0;
  1870.                         stack[loc2].value := 0.0;
  1871.                     end
  1872.                 else
  1873.                     with info^ do begin
  1874.                             stack[loc1].value := PixelsPerLine;
  1875.                             stack[loc2].value := nLines;
  1876.                         end;
  1877.     end;
  1878.  
  1879.  
  1880.     procedure GetRoi;  {(hloc,vloc,width,height)}
  1881.         var
  1882.             loc1, loc2, loc3, loc4: integer;
  1883.     begin
  1884.         GetLeftParen;
  1885.         loc1 := GetVar;
  1886.         GetComma;
  1887.         loc2 := GetVar;
  1888.         GetComma;
  1889.         loc3 := GetVar;
  1890.         GetComma;
  1891.         loc4 := GetVar;
  1892.         GetRightParen;
  1893.         if Token <> DoneT then
  1894.             with MacrosP^, Info^ do
  1895.                 if RoiShowing then
  1896.                     with RoiRect do begin
  1897.                             stack[loc1].value := left;
  1898.                             stack[loc2].value := top;
  1899.                             stack[loc3].value := right - left;
  1900.                             stack[loc4].value := bottom - top;
  1901.                         end
  1902.                 else begin
  1903.                         stack[loc1].value := 0.0;
  1904.                         stack[loc2].value := 0.0;
  1905.                         stack[loc3].value := 0.0;
  1906.                         stack[loc4].value := 0.0;
  1907.                     end;
  1908.     end;
  1909.  
  1910.  
  1911.     procedure CaptureOneFrame;
  1912.     begin
  1913.         if FrameGrabber = noFrameGrabber then
  1914.             MacroError('Frame grabber not installed')
  1915.         else begin
  1916.                 StartDigitizing;
  1917.                 CaptureAndDisplayFrame;
  1918.                 StopDigitizing;
  1919.             end;
  1920.     end;
  1921.  
  1922.  
  1923.     procedure DoMakeNewWindow; {(name:str255)}
  1924.         var
  1925.             name: str255;
  1926.     begin
  1927.         GetArguments(name);
  1928.         if token <> DoneT then
  1929.             if (NewPicWidth * NewPicHeight) > UndoBufSize then
  1930.                 MacroError('New window larger than Undo buffer')
  1931.             else if not NewPicWindow(name, NewPicWidth, NewPicHeight) then
  1932.                 MacroError('Out of memory');
  1933.     end;
  1934.  
  1935.  
  1936.     procedure DoSetPalette;
  1937.         var
  1938.             PaletteType: str255;
  1939.             ok, OptionalArgument: boolean;
  1940.             nExtra: LongInt;
  1941.     begin
  1942.         GetLeftParen;
  1943.         PaletteType := GetString;
  1944.         GetToken;
  1945.         OptionalArgument := token <> RightParen;
  1946.         PutTokenBack;
  1947.         if OptionalArgument then begin
  1948.                 GetComma;
  1949.                 nExtra := GetInteger;
  1950.                 if nExtra < 0 then
  1951.                     nExtra := 0;
  1952.                 if nExtra > 6 then
  1953.                     nExtra := 6;
  1954.         end;
  1955.         GetRightParen;
  1956.         if token <> DoneT then begin
  1957.                 MakeLowerCase(PaletteType);
  1958.                 if pos('gray', PaletteType) <> 0 then
  1959.                     ResetGrayMap
  1960.                 else if pos('pseudo', PaletteType) <> 0 then
  1961.                     SwitchColorTables(Pseudo20Item, true)
  1962.                 else if pos('system', PaletteType) <> 0 then
  1963.                     SwitchColorTables(SystemPaletteItem, true)
  1964.                 else if pos('rainbow', PaletteType) <> 0 then
  1965.                     SwitchColorTables(RainbowItem, true)
  1966.                 else if pos('spectrum', PaletteType) <> 0 then
  1967.                     SwitchColorTables(SpectrumItem, true);
  1968.                 if OptionalArgument then begin
  1969.                     nExtraColors := nExtra;
  1970.                     RedrawLUTWindow;
  1971.                 end;
  1972.             end;
  1973.     end;
  1974.  
  1975.  
  1976.     procedure DoOpenImage;
  1977.         var
  1978.             err: OSErr;
  1979.             f: integer;
  1980.             FileFound, result: boolean;
  1981.             fname: str255;
  1982.             SaveCommand: CommandType;
  1983.     begin
  1984.         SaveCommand := MacroCommand;
  1985.         GetArguments(fname);
  1986.         if token <> DoneT then begin
  1987.                 if fname = '' then
  1988.                     fname := DefaultFileName;
  1989.                 err := fsopen(fname, DefaultRefNum, f);
  1990.                 FileFound := err = NoErr;
  1991.                 err := fsclose(f);
  1992.                 if FileFound then
  1993.                     case SaveCommand of
  1994.                         OpenC: 
  1995.                             result := DoOpen(fname, DefaultRefNum);
  1996.                         ImportC: 
  1997.                             result := ImportFile(fname, DefaultRefNum);
  1998.                     end
  1999.                 else
  2000.                     case SaveCommand of
  2001.                         OpenC: 
  2002.                             result := DoOpen('', 0);
  2003.                         ImportC: 
  2004.                             result := ImportFile('', 0);
  2005.                     end;
  2006.                 if result then
  2007.                     UpdatePicWindow
  2008.                 else
  2009.                     token := DoneT;
  2010.             end;
  2011.     end;
  2012.  
  2013.  
  2014.     procedure SetImportAttributes;
  2015.         var
  2016.             Attributes: str255;
  2017.     begin
  2018.         Attributes := GetStringArg;
  2019.         if Token <> DoneT then begin
  2020.                 MakeLowerCase(Attributes);
  2021.                 WhatToImport := ImportTIFF;
  2022.                 ImportCustomDepth := EightBits;
  2023.                 ImportSwapBytes := false;
  2024.                 ImportCalibrate := false;
  2025.                 ImportAll := false;
  2026.                 ImportAutoScale := true;
  2027.                 ImportInvert := false;
  2028.                 if pos('dicom', Attributes) <> 0 then
  2029.                     WhatToImport := ImportDICOM;
  2030.                 if pos('mcid', Attributes) <> 0 then
  2031.                     WhatToImport := ImportMCID;
  2032.                 if pos('look', Attributes) <> 0 then
  2033.                     WhatToImport := ImportLUT;
  2034.                 if pos('palette', Attributes) <> 0 then
  2035.                     WhatToImport := ImportLUT;
  2036.                 if pos('text', Attributes) <> 0 then
  2037.                     WhatToImport := ImportText;
  2038.                 if pos('custom', Attributes) <> 0 then
  2039.                     WhatToImport := ImportCustom;
  2040.                 if (pos('8', Attributes) <> 0) or (pos('eight', Attributes) <> 0) then begin
  2041.                         ImportCustomDepth := EightBits;
  2042.                         WhatToImport := ImportCustom;
  2043.                     end;
  2044.                 if (pos('signed', Attributes) <> 0) then begin
  2045.                         ImportCustomDepth := SixteenBitsSigned;
  2046.                         WhatToImport := ImportCustom;
  2047.                     end;
  2048.                 if (pos('unsigned', Attributes) <> 0) then begin
  2049.                         ImportCustomDepth := SixteenBitsUnsigned;
  2050.                         WhatToImport := ImportCustom;
  2051.                     end;
  2052.                 if (pos('swap', Attributes) <> 0) then
  2053.                     ImportSwapBytes := true;
  2054.                 if (pos('calibrate', Attributes) <> 0) then
  2055.                     ImportCalibrate := true;
  2056.                 if (pos('fixed', Attributes) <> 0) then
  2057.                     ImportAutoScale := false;
  2058.                 if (pos('all', Attributes) <> 0) then
  2059.                     ImportAll := true;
  2060.                 if (pos('invert', Attributes) <> 0) then
  2061.                     ImportInvert := true;
  2062.             end;
  2063.     end;
  2064.  
  2065.  
  2066.     procedure SetImportMinMax; {(min,max:integer)}
  2067.         var
  2068.             TempMin, TempMax: extended;
  2069.     begin
  2070.         GetLeftParen;
  2071.         TempMin := GetExpression;
  2072.         GetComma;
  2073.         TempMax := GetExpression;
  2074.         GetRightParen;
  2075.         if Token <> DoneT then begin
  2076.                 ImportAutoScale := false;
  2077.                 ImportMin := TempMin;
  2078.                 ImportMax := TempMax;
  2079.             end;
  2080.     end;
  2081.  
  2082.  
  2083.     procedure SetCustomImport; {(width,height,offset[,nslices]:integer)}
  2084.         var
  2085.             width, height, nSlices: integer;
  2086.             offset: LongInt;
  2087.     begin
  2088.         GetLeftParen;
  2089.         width := GetInteger;
  2090.         GetComma;
  2091.         height := GetInteger;
  2092.         GetComma;
  2093.         offset := GetInteger;
  2094.         GetToken;
  2095.         if token = comma then
  2096.             nSlices := GetInteger
  2097.         else begin
  2098.                 PutTokenBack;
  2099.                 nSlices := 1
  2100.             end;
  2101.         GetRightParen;
  2102.         if (width < 0) or (width > MaxPicSize) or (height < 0) or (offset < 0) or (nSlices < 1) then
  2103.             MacroError('Argument out of range');
  2104.         if Token <> DoneT then begin
  2105.                 ImportCustomWidth := width;
  2106.                 ImportCustomHeight := height;
  2107.                 ImportCustomOffset := offset;
  2108.                 ImportCustomSlices := nSlices;
  2109.                 WhatToImport := ImportCustom;
  2110.             end;
  2111.     end;
  2112.  
  2113.  
  2114.     procedure SelectImage (id: integer);
  2115.     begin
  2116.         StopDigitizing;
  2117.         SaveRoi;
  2118.         DisableDensitySlice;
  2119.         SelectWindow(PicWindow[id]);
  2120.         Info := pointer(WindowPeek(PicWindow[id])^.RefCon);
  2121.         ActivateWindow;
  2122.         GenerateValues;
  2123.         LoadLUT(info^.cTable);
  2124.         UpdatePicWindow;
  2125.     end;
  2126.  
  2127.  
  2128.     procedure SelectPic; {(PicN:integer)}
  2129.         var
  2130.             PicN, i: integer;
  2131.             SaveCommand: CommandType;
  2132.     begin
  2133.         SaveCommand := MacroCommand;
  2134.         GetLeftParen;
  2135.         PicN := GetInteger;
  2136.         GetRightParen;
  2137.         i := 0;
  2138.         while (PicN < 0) and (i < nPics) do begin
  2139.                 i := i + 1;
  2140.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  2141.                     PicN := i;
  2142.             end;
  2143.         if (PicN < 1) or (PicN > nPics) then
  2144.             MacroError('Specified image does not exist');
  2145.         if Token <> DoneT then begin
  2146.                 if SaveCommand = SelectPicC then
  2147.                     SelectImage(PicN)
  2148.                 else begin
  2149.                         StopDigitizing;
  2150.                         DisableDensitySlice;
  2151.                         Info := pointer(WindowPeek(PicWindow[PicN])^.RefCon);
  2152.                     end;
  2153.             end;
  2154.     end;
  2155.  
  2156.  
  2157.     procedure SetPicName;  {(name:string)}
  2158.         var
  2159.             n, i: LongInt;
  2160.             isInteger: boolean;
  2161.             name: str255;
  2162.     begin
  2163.         GetArguments(name);
  2164.         if Token <> DoneT then begin
  2165.                 with info^ do begin
  2166.                         title := name;
  2167.                         if PictureType <> FrameGrabberType then
  2168.                             PictureType := NewPicture;
  2169.                         UpdateWindowsMenuItem;
  2170.                         UpdateTitleBar;
  2171.                     end;
  2172.             end;
  2173.     end;
  2174.  
  2175.  
  2176.     procedure SetNewSize; {(width,height:integer)}
  2177.         var
  2178.             TempWidth, TempHeight: integer;
  2179.     begin
  2180.         GetLeftParen;
  2181.         TempWidth := GetInteger;
  2182.         GetComma;
  2183.         TempHeight := GetInteger;
  2184.         GetRightParen;
  2185.         if Token <> DoneT then begin
  2186.                 NewPicWidth := TempWidth;
  2187.                 NewPicHeight := TempHeight;
  2188.                 if NewPicWidth > MaxPicSize then
  2189.                     NewPicWidth := MaxPicSize;
  2190.                 if NewPicWidth < 8 then
  2191.                     NewPicWidth := 8;
  2192.                 if NewPicHeight < 8 then
  2193.                     NewPicHeight := 8;
  2194.                 if NewPicHeight > MaxPicSize then
  2195.                     NewPicHeight := MaxPicSize;
  2196.             end;
  2197.     end;
  2198.  
  2199.  
  2200.     procedure DoSaveAs;
  2201.         var
  2202.             name: str255;
  2203.             RefNum: integer;
  2204.             HasArgs: boolean;
  2205.     begin
  2206.         name := info^.title;
  2207.         if (name = 'Untitled') or (name = 'Camera') then
  2208.             name := '';
  2209.         GetToken;
  2210.         HasArgs := token = LeftParen;
  2211.         PutTokenBack;
  2212.         if HasArgs then
  2213.             GetArguments(name);
  2214.         if token <> DoneT then begin
  2215.                 StopDigitizing;
  2216.                 if nSaves = 0 then
  2217.                     RefNum := 0
  2218.                 else
  2219.                     RefNum := DefaultRefNum;
  2220.                 case CurrentWindow of
  2221.                     TextKind: 
  2222.                         if pos(':', name) <> 0 then
  2223.                             SaveTextUsingPath(name)
  2224.                         else
  2225.                             SaveTextAs;
  2226.                     ResultsKind: 
  2227.                         Export('', RefNum);
  2228.                     otherwise begin
  2229.                             if info <> NoInfo then
  2230.                                 SaveAs(name, RefNum)
  2231.                             else
  2232.                                 MacroError(NoImageOpen);
  2233.                         end;
  2234.                 end;
  2235.                 nSaves := nSaves + 1;
  2236.             end;
  2237.     end;
  2238.  
  2239.  
  2240.     procedure DoSave;
  2241.         var
  2242.             kind: integer;
  2243.     begin
  2244.         StopDigitizing;
  2245.         kind := CurrentWindow;
  2246.         if (kind = PicKind) or (kind = TextKind) or (Kind = ResultsKind) then
  2247.             SaveFile
  2248.         else
  2249.             MacroError('Nothing to save');
  2250.     end;
  2251.  
  2252.  
  2253.     procedure DoExport;
  2254.         var
  2255.             name: str255;
  2256.             RefNum: integer;
  2257.             HasArgs: boolean;
  2258.     begin
  2259.         StopDigitizing;
  2260.         name := info^.title;
  2261.         if (name = 'Untitled') or (name = 'Camera') then
  2262.             name := '';
  2263.         GetToken;
  2264.         HasArgs := token = LeftParen;
  2265.         PutTokenBack;
  2266.         if HasArgs then
  2267.             GetArguments(name);
  2268.         if nSaves = 0 then
  2269.             RefNum := 0
  2270.         else
  2271.             RefNum := DefaultRefNum;
  2272.         Export(name, RefNum);
  2273.         nSaves := nSaves + 1;
  2274.     end;
  2275.  
  2276.  
  2277.     procedure DoCopyResults;
  2278.         var
  2279.             IgnoreResult: boolean;
  2280.     begin
  2281.         if mCount < 1 then
  2282.             MacroError('Copy Results failed')
  2283.         else begin
  2284.                 CopyResults;
  2285.                 IgnoreResult := SystemEdit(3); {Fake Copy needed for MultiFinder}
  2286.             end;
  2287.     end;
  2288.  
  2289.  
  2290.     procedure DisposeAll;
  2291.         var
  2292.             i, ignore: integer;
  2293.     begin
  2294.         StopDigitizing;
  2295.         for i := nPics downto 1 do begin
  2296.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  2297.                 ignore := CloseAWindow(info^.wptr);
  2298.             end;
  2299.     end;
  2300.  
  2301.  
  2302.     procedure DoDuplicate;
  2303.         var
  2304.             str: str255;
  2305.     begin
  2306.         GetArguments(str);
  2307.         if token <> DoneT then
  2308.             if not Duplicate(str, false) then
  2309.                 token := DoneT
  2310.             else
  2311.                 UpdatePicWindow;
  2312.     end;
  2313.  
  2314.  
  2315.     procedure DoLineTo; {(x,y:integer)}
  2316.         var
  2317.             x, y: integer;
  2318.             p1, p2: point;
  2319.     begin
  2320.         GetLeftParen;
  2321.         p2.h := GetInteger;
  2322.         GetComma;
  2323.         p2.v := GetInteger;
  2324.         GetRightParen;
  2325.         if token <> DoneT then begin
  2326.                 KillRoi;
  2327.                 p1.h := CurrentX;
  2328.                 p1.v := CurrentY;
  2329.                 CurrentX := p2.h;
  2330.                 CurrentY := p2.v;
  2331.                 OffscreenToScreen(p1);
  2332.                 OffscreenToScreen(p2);
  2333.                 DrawObject(LineObj, p1, p2);
  2334.             end;
  2335.     end;
  2336.  
  2337.  
  2338.     procedure DoGetLine;  {(var x1,y1,x2,y2:real; LineWidth:integer)}
  2339.         var
  2340.             loc1, loc2, loc3, loc4, loc5: integer;
  2341.             x1, y1, x2, y2: extended;
  2342.     begin
  2343.         GetLeftParen;
  2344.         loc1 := GetVar;
  2345.         GetComma;
  2346.         loc2 := GetVar;
  2347.         GetComma;
  2348.         loc3 := GetVar;
  2349.         GetComma;
  2350.         loc4 := GetVar;
  2351.         GetComma;
  2352.         loc5 := GetVar;
  2353.         GetRightParen;
  2354.         if Token <> DoneT then
  2355.             with MacrosP^, info^ do begin
  2356.                     GetLoi(x1, y1, x2, y2);
  2357.                     if RoiShowing and (RoiType = LineRoi) then
  2358.                         stack[loc1].value := x1
  2359.                     else
  2360.                         stack[loc1].value := -1;
  2361.                     stack[loc2].value := y1;
  2362.                     stack[loc3].value := x2;
  2363.                     stack[loc4].value := y2;
  2364.                     stack[loc5].value := LineWidth;
  2365.                 end;
  2366.     end;
  2367.  
  2368.  
  2369.     procedure DoScaleAndRotate; {(hscale,vscale,angle:real)}
  2370.         var
  2371.             SaveCommand: CommandType;
  2372.     begin
  2373.         SaveCommand := MacroCommand;
  2374.         GetLeftParen;
  2375.         rsHScale := GetExpression;
  2376.         GetComma;
  2377.         rsVScale := GetExpression;
  2378.         if SaveCommand <> ScaleSelectionC then begin
  2379.                 GetComma;
  2380.                 rsAngle := GetExpression;
  2381.             end;
  2382.         GetRightParen;
  2383.         if token <> DoneT then begin
  2384.                 if SaveCommand = ScaleSelectionC then begin
  2385.                         rsMethod := NearestNeighbor;
  2386.                         rsCreateNewWindow := false;
  2387.                         rsAngle := 0.0;
  2388.                     end;
  2389.                 ScaleAndRotate;
  2390.             end;
  2391.     end;
  2392.  
  2393.  
  2394.     procedure SetPlotScale; {(min,max:integer)}
  2395.         var
  2396.             min, max: extended;
  2397.     begin
  2398.         GetLeftParen;
  2399.         min := GetExpression;
  2400.         GetComma;
  2401.         max := GetExpression;
  2402.         GetRightParen;
  2403.         if info^.fit = uncalibrated then begin
  2404.                 RangeCheck(trunc(min));
  2405.                 RangeCheck(trunc(max));
  2406.             end;
  2407.         if token <> DoneT then begin
  2408.                 AutoScalePlots := (min = 0.0) and (max = 0.0);
  2409.                 ProfilePlotMin := min;
  2410.                 ProfilePlotMax := max;
  2411.             end;
  2412.     end;
  2413.  
  2414.  
  2415.     procedure SetPlotDimensions; {(width,height:integer)}
  2416.         var
  2417.             width, height: integer;
  2418.     begin
  2419.         GetLeftParen;
  2420.         width := GetInteger;
  2421.         GetComma;
  2422.         height := GetInteger;
  2423.         GetRightParen;
  2424.         if token <> DoneT then begin
  2425.                 FixedSizePlot := not ((width = 0) and (height = 0));
  2426.                 ProfilePlotWidth := width;
  2427.                 ProfilePlotHeight := height;
  2428.             end;
  2429.     end;
  2430.  
  2431.  
  2432.     procedure GetResults;  {(var n,mean,mode,min,max:real)}
  2433.         var
  2434.             loc1, loc2, loc3, loc4, loc5: integer;
  2435.     begin
  2436.         GetLeftParen;
  2437.         loc1 := GetVar;
  2438.         GetComma;
  2439.         loc2 := GetVar;
  2440.         GetComma;
  2441.         loc3 := GetVar;
  2442.         GetComma;
  2443.         loc4 := GetVar;
  2444.         GetComma;
  2445.         loc5 := GetVar;
  2446.         GetRightParen;
  2447.         if mCount = 0 then
  2448.             MacroError('No results');
  2449.         if Token <> DoneT then
  2450.             with MacrosP^, results do begin
  2451.                     stack[loc1].value := PixelCount^[mCount];
  2452.                     stack[loc2].value := UncalibratedMean;
  2453.                     stack[loc3].value := imode;
  2454.                     stack[loc4].value := MinIndex;
  2455.                     stack[loc5].value := MaxIndex;
  2456.                 end;
  2457.     end;
  2458.  
  2459.  
  2460.     procedure DoPasteOperation;
  2461.     begin
  2462.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  2463.                 MacroError('Not pasting');
  2464.                 exit(DoPasteOperation);
  2465.             end;
  2466.         if MacroCommand in [AddC, SubC, MulC, DivC] then begin
  2467.                 case MacroCommand of
  2468.                     AddC: 
  2469.                         CurrentOp := AddOp;
  2470.                     SubC: 
  2471.                         CurrentOp := SubtractOp;
  2472.                     MulC: 
  2473.                         CurrentOp := MultiplyOp;
  2474.                     DivC: 
  2475.                         CurrentOp := DivideOp;
  2476.                 end;
  2477.                 DoPasteMath;
  2478.                 exit(DoPasteOperation);
  2479.             end;
  2480.         SetForegroundColor(BlackIndex);
  2481.         SetBackGroundColor(WhiteIndex);
  2482.         case MacroCommand of
  2483.             CopyModeC: 
  2484.                 SetPasteMode(CopyModeItem);
  2485.             AndC: 
  2486.                 SetPasteMode(AndItem);
  2487.             OrC: 
  2488.                 SetPasteMode(OrItem);
  2489.             XorC: 
  2490.                 SetPasteMode(XorItem);
  2491.             ReplaceC: 
  2492.                 SetPasteMode(ReplaceItem);
  2493.             BlendC: 
  2494.                 SetPasteMode(BlendItem);
  2495.         end;
  2496.         if OptionKeyWasDown then begin
  2497.                 if PasteControl <> nil then
  2498.                     DrawPasteControl;
  2499.             end
  2500.         else
  2501.             KillRoi;
  2502.     end;
  2503.  
  2504.  
  2505.     procedure SetWidth; {(width:integer)}
  2506.         var
  2507.             width: integer;
  2508.     begin
  2509.         GetLeftParen;
  2510.         width := GetInteger;
  2511.         GetRightParen;
  2512.         if (Token <> DoneT) and (width > 0) then begin
  2513.                 LineWidth := width;
  2514.                 ShowLIneWidth;
  2515.             end;
  2516.     end;
  2517.  
  2518.  
  2519.     function GetMType (index: integer): MeasurementTypes;
  2520.     begin
  2521.         case index of
  2522.             0: 
  2523.                 GetMType := AreaM;
  2524.             1: 
  2525.                 GetMType := MeanM;
  2526.             2: 
  2527.                 GetMType := StdDevM;
  2528.             3: 
  2529.                 GetMType := xyLocM;
  2530.             4: 
  2531.                 GetMType := ModeM;
  2532.             5: 
  2533.                 GetMType := LengthM;
  2534.             6: 
  2535.                 GetMType := MajorAxisM;
  2536.             7: 
  2537.                 GetMType := MinorAxisM;
  2538.             8: 
  2539.                 GetMType := AngleM;
  2540.             9: 
  2541.                 GetMType := IntDenM;
  2542.             10: 
  2543.                 GetMType := MinMaxM;
  2544.             11: 
  2545.                 GetMType := User1M;
  2546.             12: 
  2547.                 GetMType := User2M;
  2548.         end;
  2549.     end;
  2550.  
  2551.  
  2552.     procedure SetPrecision; {(DigitsRightofDecimalPoint[,FieldWidth]:integer)}
  2553.         var
  2554.             digits, width: LongInt;
  2555.     begin
  2556.         GetLeftParen;
  2557.         digits := GetInteger;
  2558.         GetToken;
  2559.         if token = comma then
  2560.             width := GetInteger
  2561.         else
  2562.             PutTokenBack;
  2563.         GetRightParen;
  2564.         if Token <> DoneT then begin
  2565.                 if (digits >= 0) and (digits <= 12) then
  2566.                     precision := digits;
  2567.                 if (width >= 1) and (width <= 18) then
  2568.                     FieldWidth := width;
  2569.             end;
  2570.     end;
  2571.  
  2572.  
  2573.     procedure SetParticleSize; {(min,max:LongInt)}
  2574.         var
  2575.             min, max: LongInt;
  2576.     begin
  2577.         GetLeftParen;
  2578.         min := GetInteger;
  2579.         GetComma;
  2580.         max := GetInteger;
  2581.         GetRightParen;
  2582.         if Token <> DoneT then begin
  2583.                 MinParticleSize := min;
  2584.                 MaxParticleSize := max;
  2585.             end;
  2586.     end;
  2587.  
  2588.  
  2589.     procedure SetThreshold; {(level:integer)}
  2590.         var
  2591.             level: LongInt;
  2592.     begin
  2593.         GetLeftParen;
  2594.         level := GetInteger;
  2595.         GetRightParen;
  2596.         if level = -1 then begin
  2597.                 DisableThresholding;
  2598.                 exit(SetThreshold);
  2599.             end;
  2600.         RangeCheck(level);
  2601.         if Token <> DoneT then
  2602.             EnableThresholding(level);
  2603.     end;
  2604.  
  2605.  
  2606.     procedure DoPutPixel; {(hloc,vloc, value:integer)}
  2607.         var
  2608.             hloc, vloc: LongInt;
  2609.             value: integer;
  2610.             MaskRect: rect;
  2611.     begin
  2612.         GetLeftParen;
  2613.         hloc := GetInteger;
  2614.         GetComma;
  2615.         vloc := GetInteger;
  2616.         GetComma;
  2617.         value := GetInteger;
  2618.         GetRightParen;
  2619.         if (Token <> DoneT) and (info <> NoInfo) then begin
  2620.                 KillRoi;
  2621.                 PutPixel(hloc, vloc, value);
  2622.                 SetRect(MaskRect, hloc, vloc, hloc + 1, vloc + 1);
  2623.                 UpdateScreen(MaskRect);
  2624.                 info^.changes := true;
  2625.             end;
  2626.     end;
  2627.  
  2628.  
  2629.     procedure CloseWindow;
  2630.         var
  2631.             OldPicNum, NewPicNum, ignore: integer;
  2632.     begin
  2633.         if CurrentWindow <> PicKind then begin
  2634.                 ignore := CloseAWindow(CurrentWPtr);
  2635.                 exit(CloseWindow);
  2636.             end;
  2637.         if info = NoInfo then begin
  2638.                 MacroError(NoImageOpen);
  2639.                 exit(CloseWindow);
  2640.             end;
  2641.         StopDigitizing;
  2642.         SaveRoi;
  2643.         with info^ do begin
  2644.                 OldPicNum := PicNum;
  2645.                 ignore := CloseAWindow(wptr);
  2646.             end;
  2647.         if nPics >= 1 then begin
  2648.                 NewPicNum := OldPicNum - 1;
  2649.                 if NewPicNum < 1 then
  2650.                     NewPicNum := 1;
  2651.                 SelectImage(NewPicNum);
  2652.             end;
  2653.     end;
  2654.  
  2655.  
  2656.     procedure SetScaling;
  2657.         var
  2658.             ScalingOptions: str255;
  2659.             ok: boolean;
  2660.     begin
  2661.         ScalingOptions := GetStringArg;
  2662.         if token <> DoneT then begin
  2663.                 MakeLowerCase(ScalingOptions);
  2664.                 rsInteractive := false;
  2665.                 if pos('bilinear', ScalingOptions) <> 0 then
  2666.                     rsMethod := Bilinear;
  2667.                 if pos('nearest', ScalingOptions) <> 0 then
  2668.                     rsMethod := NearestNeighbor;
  2669.                 if pos('new', ScalingOptions) <> 0 then
  2670.                     rsCreateNewWindow := true;
  2671.                 if pos('same', ScalingOptions) <> 0 then
  2672.                     rsCreateNewWindow := false;
  2673.                 if pos('interactive', ScalingOptions) <> 0 then
  2674.                     rsInteractive := true;
  2675.             end;
  2676.     end;
  2677.  
  2678.  
  2679.     procedure DoChangeValues; {(v1,v2,v3:integer)}
  2680.         var
  2681.             v1, v2, v3: integer;
  2682.     begin
  2683.         GetLeftParen;
  2684.         v1 := GetInteger;
  2685.         GetComma;
  2686.         v2 := GetInteger;
  2687.         GetComma;
  2688.         v3 := GetInteger;
  2689.         GetRightParen;
  2690.         RangeCheck(v1);
  2691.         RangeCheck(v2);
  2692.         RangeCheck(v3);
  2693.         if Token <> DoneT then
  2694.             ChangeValues(v1, v2, v3);
  2695.     end;
  2696.  
  2697.  
  2698.     procedure DoGetMouse;  {(var x,y:integer)}
  2699.         var
  2700.             loc1, loc2, sh, sv: integer;
  2701.             loc: point;
  2702.     begin
  2703.         GetLeftParen;
  2704.         loc1 := GetVar;
  2705.         GetComma;
  2706.         loc2 := GetVar;
  2707.         GetRightParen;
  2708.         if Token <> DoneT then
  2709.             with MacrosP^ do begin
  2710.                     SetPort(info^.wptr);
  2711.                     GetMouse(loc);
  2712.                     with loc do begin
  2713.                             sh := h;
  2714.                             sv := v;
  2715.                             ScreenToOffscreen(loc);
  2716.                             if sh < 0 then
  2717.                                 h := sh;
  2718.                             if sv < 0 then
  2719.                                 v := sv;
  2720.                             stack[loc1].value := h;
  2721.                             stack[loc2].value := v;
  2722.                         end;
  2723.                 end;
  2724.     end;
  2725.  
  2726.  
  2727.     procedure DoRotate (cmd: CommandType);
  2728.         var
  2729.             NoBoolean, NewWindow: boolean;
  2730.     begin
  2731.         GetToken;
  2732.         noBoolean := token <> LeftParen;
  2733.         PutTokenBack;
  2734.         if NoBoolean then
  2735.             NewWindow := false
  2736.         else
  2737.             NewWindow := GetBooleanArg;
  2738.         if NewWindow then begin
  2739.                 case cmd of
  2740.                     RotateRC: 
  2741.                         RotateToNewWindow(RotateRight);
  2742.                     RotateLC: 
  2743.                         RotateToNewWindow(RotateLeft)
  2744.                 end;
  2745.                 if not macro then
  2746.                     MacroError('Rotate failed')
  2747.             end
  2748.         else
  2749.             case cmd of
  2750.                 RotateRC: 
  2751.                     FlipOrRotate(RotateRight);
  2752.                 RotateLC: 
  2753.                     FlipOrRotate(RotateLeft)
  2754.             end;
  2755.     end;
  2756.  
  2757.  
  2758.     procedure DoSelectSlice; {(SliceNumber:integer)}
  2759.         var
  2760.             SliceNumber: LongInt;
  2761.             isRoi: boolean;
  2762.             SaveCommand: CommandType;
  2763.     begin
  2764.         SaveCommand := MacroCommand;
  2765.         GetLeftParen;
  2766.         SliceNumber := GetInteger;
  2767.         GetRightParen;
  2768.         with info^, info^.StackInfo^ do begin
  2769.                 if (SliceNumber < 1) or (SliceNumber > nSlices) then
  2770.                     MacroError('Illegal slice number');
  2771.                 if Token <> DoneT then begin
  2772.                         isRoi := RoiShowing;
  2773.                         if isRoi then
  2774.                             KillRoi;
  2775.                         CurrentSlice := SliceNumber;
  2776.                         SelectSlice(CurrentSlice);
  2777.                         if SaveCommand = SelectSliceC then begin
  2778.                                 UpdatePicWindow;
  2779.                                 UpdateTitleBar;
  2780.                             end;
  2781.                         if isRoi then
  2782.                             RestoreRoi;
  2783.                     end;
  2784.             end;
  2785.     end;
  2786.  
  2787.  
  2788.     procedure MakeNewStack; {(name:str255)}
  2789.         var
  2790.             name: str255;
  2791.             aok: boolean;
  2792.     begin
  2793.         GetArguments(name);
  2794.         if token <> DoneT then
  2795.             if (NewPicWidth * NewPicHeight) > UndoBufSize then
  2796.                 MacroError('Stack larger than Undo Buffer')
  2797.             else if NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2798.                 if not MakeStackFromWindow then
  2799.                     MacroError('Out of memory');
  2800.     end;
  2801.  
  2802.  
  2803.     procedure MakeLineRoi; {(x1,y1,x2,y2:real)}
  2804.         var
  2805.             x1, y1, x2, y2: extended;
  2806.     begin
  2807.         GetLeftParen;
  2808.         x1 := GetExpression;
  2809.         GetComma;
  2810.         y1 := GetExpression;
  2811.         GetComma;
  2812.         x2 := GetExpression;
  2813.         GetComma;
  2814.         y2 := GetExpression;
  2815.         GetRightParen;
  2816.         if token <> DoneT then
  2817.             with Info^ do begin
  2818.                     KillRoi;
  2819.                     StopDigitizing;
  2820.                     LX1 := x1;
  2821.                     LY1 := y1;
  2822.                     LX2 := x2;
  2823.                     LY2 := y2;
  2824.                     RoiType := LineRoi;
  2825.                     MakeRegion;
  2826.                     SetupUndo;
  2827.                     RoiShowing := true;
  2828.                 end;
  2829.     end;
  2830.  
  2831.  
  2832.     procedure DoGetTime;
  2833.         var
  2834.             date: DateTimeRec;
  2835.             loc1, loc2, loc3, loc4, loc5, loc6, loc7: integer;
  2836.     begin
  2837.         GetLeftParen;
  2838.         loc1 := GetVar;
  2839.         GetComma;
  2840.         loc2 := GetVar;
  2841.         GetComma;
  2842.         loc3 := GetVar;
  2843.         GetComma;
  2844.         loc4 := GetVar;
  2845.         GetComma;
  2846.         loc5 := GetVar;
  2847.         GetComma;
  2848.         loc6 := GetVar;
  2849.         GetComma;
  2850.         loc7 := GetVar;
  2851.         GetRightParen;
  2852.         if Token <> DoneT then
  2853.             with MacrosP^, info^ do begin
  2854.                     GetTime(date);
  2855.                     with date do begin
  2856.                             stack[loc1].value := year;
  2857.                             stack[loc2].value := month;
  2858.                             stack[loc3].value := day;
  2859.                             stack[loc4].value := hour;
  2860.                             stack[loc5].value := minute;
  2861.                             stack[loc6].value := second;
  2862.                             stack[loc7].value := DayOfWeek;
  2863.                         end;
  2864.                 end;
  2865.     end;
  2866.  
  2867.  
  2868.     function GetStringVar: integer;
  2869.     begin
  2870.         GetStringVar := 0;
  2871.         GetToken;
  2872.         if token <> StringVariable then
  2873.             MacroError('String variable expected')
  2874.         else
  2875.             GetStringVar := TokenStackLoc;
  2876.     end;
  2877.  
  2878.  
  2879.     procedure DoSetScale; {(scale:real; unit:string; [AspectRatio: real])}
  2880.         var
  2881.             id: integer;
  2882.             scale, AspectRatio: extended;
  2883.             str: str255;
  2884.     begin
  2885.         AspectRatio:=0.0;
  2886.         GetLeftParen;
  2887.         scale := GetExpression;
  2888.         GetComma;
  2889.         str := GetString;
  2890.         GetToken;
  2891.         if token=comma
  2892.             then AspectRatio:=GetExpression
  2893.             else PutTokenBack;
  2894.         GetRightParen;
  2895.         if token <> DoneT then
  2896.             with info^ do begin
  2897.                     if str = '' then begin
  2898.                             SetScale; {Display Set Scale dialog box}
  2899.                             exit(DoSetScale);
  2900.                         end;
  2901.                     if scale < 0.0 then begin
  2902.                             MacroError('Scale<0');
  2903.                             exit(DoSetScale);
  2904.                         end;
  2905.                     MakeLowerCase(str);
  2906.                     TruncateString(str, maxUnit);
  2907.                     xUnit := str;
  2908.                     xScale := scale;
  2909.                     yScale := scale;
  2910.                     if AspectRatio>0.0 then begin
  2911.                         PixelAspectRatio:=AspectRatio;
  2912.                         yScale := xScale / PixelAspectRatio;
  2913.                     end else
  2914.                         PixelAspectRatio := 1.0;
  2915.                     SpatiallyCalibrated := (xUnit <> '') and (xUnit <> 'pixel') and (xUnit <> 'pixels') and (xScale <> 0.0);
  2916.                     UpdateTitleBar;
  2917.                 end;
  2918.     end;
  2919.  
  2920.  
  2921.     procedure GetScale;  {(var scale:real; unit:string; [AspectRatio:real])}
  2922.         var
  2923.             loc1, loc2, loc3, index, count: integer;
  2924.             str: str255;
  2925.     begin
  2926.         GetLeftParen;
  2927.         loc1 := GetVar;
  2928.         GetComma;
  2929.         loc2 := GetStringVar;
  2930.         loc3:=0;
  2931.         GetToken;
  2932.         if token=comma
  2933.          then loc3 := GetVar
  2934.          else PutTokenBack;
  2935.         GetRightParen;
  2936.         if Token <> DoneT then
  2937.             with info^, MacrosP^ do
  2938.                 if SpatiallyCalibrated then begin
  2939.                         stack[loc1].value := xScale;
  2940.                         stack[loc2].StringH^^ := xUnit;
  2941.                         if loc3>0 then stack[loc3].value := PixelAspectRatio;
  2942.                     end
  2943.                 else begin
  2944.                         stack[loc1].value := 1.0;
  2945.                         stack[loc2].StringH^^ := 'pixel';
  2946.                         if loc3>0 then stack[loc3].value := 1.0;
  2947.                     end;
  2948.     end;
  2949.  
  2950.  
  2951.     procedure SaveState;
  2952.     begin
  2953.         SaveForeground := ForegroundIndex;
  2954.         SaveBackground := BackgroundIndex;
  2955.         SavePicWidth := NewPicWidth;
  2956.         SavePicHeight := NewPicHeight;
  2957.         SaveMethod := rsMethod;
  2958.         SaveCreate := rsCreateNewWindow;
  2959.         SaveAngle := rsAngle;
  2960.         SaveH := rsHScale;
  2961.         SaveV := rsVScale;
  2962.         SaveInvertY := InvertYCoordinates;
  2963.         SaveScaleArithmetic := ScaleArithmetic;
  2964.         SaveScaleConvolutions := ScaleConvolutions;
  2965.         SaveCurrentFontID:=CurrentFontID;
  2966.         SaveCurrentSize:=CurrentSize;
  2967.         SaveCurrentStyle:=CurrentStyle;
  2968.         SaveTextJust:=TextJust;
  2969.         SaveTextBack:=TextBack;
  2970.     end;
  2971.  
  2972.  
  2973.     procedure RestoreState;
  2974.     begin
  2975.         if SaveForeground = -1 then
  2976.             MacroError('State not saved')
  2977.         else begin
  2978.                 SetForegroundColor(SaveForeground);
  2979.                 SetBackgroundColor(SaveBackground);
  2980.                 NewPicWidth := SavePicWidth;
  2981.                 NewPicHeight := SavePicHeight;
  2982.                 rsMethod := SaveMethod;
  2983.                 rsCreateNewWindow := SaveCreate;
  2984.                 rsAngle := SaveAngle;
  2985.                 rsHScale := SaveH;
  2986.                 rsVScale := SaveV;
  2987.                 InvertYCoordinates := SaveInvertY;
  2988.                 ScaleArithmetic := SaveScaleArithmetic;
  2989.                 ScaleConvolutions := SaveScaleConvolutions;
  2990.                 CurrentFontID:=SaveCurrentFontID;
  2991.                 CurrentSize:=SaveCurrentSize;
  2992.                 CurrentStyle:=SaveCurrentStyle;
  2993.                 TextJust:=SaveTextJust;
  2994.                 TextBack:=SaveTextBack;
  2995. end;
  2996.     end;
  2997.  
  2998.  
  2999.     procedure DoPrint;
  3000.     begin
  3001.         FindWhatToPrint;
  3002.         if WhatToPrint <> NothingToPrint then
  3003.             Print(false)
  3004.         else
  3005.             MacroError('NothingToPrint');
  3006.     end;
  3007.  
  3008.  
  3009.     procedure SetCounter; {(n:integer)}
  3010.         var
  3011.             N, i: LongInt;
  3012.     begin
  3013.         GetLeftParen;
  3014.         N := GetInteger;
  3015.         GetRightParen;
  3016.         if (N < 0) or (N > MaxMeasurements) then
  3017.             MacroError('Argument out of range');
  3018.         if Token <> DoneT then begin
  3019.                 if N = 0 then
  3020.                     ResetCounter;
  3021.                 for i := mCount + 1 to N do
  3022.                     ClearResults(i);
  3023.                 mCount := N;
  3024.                 UpdateList;
  3025.                 ShowInfo;
  3026.             end;
  3027.     end;
  3028.  
  3029.  
  3030.     procedure OutputText;
  3031.         var
  3032.             NewLine: boolean;
  3033.             str: str255;
  3034.             i: integer;
  3035.             SaveCommand: CommandType;
  3036.     begin
  3037.         NewLine := MacroCommand <> WriteC;
  3038.         SaveCommand := MacroCommand;
  3039.         GetArguments(str);
  3040.         if token <> DoneT then begin
  3041.                 if SaveCommand = ShowMsgC then begin
  3042.                         for i := 1 to length(str) do
  3043.                             if str[i] = '\' then
  3044.                                 str[i] := cr;
  3045.                         InfoMessage := str;
  3046.                         ShowInfo;
  3047.                     end
  3048.                 else begin
  3049.                         if CurrentWindow = TextKind then begin
  3050.                             InsertText(str, NewLine);
  3051.                             if not macro then MacroError('32K text limit exceeded')
  3052.                         end else
  3053.                             DoDrawText(str, NewLine);
  3054.                     end;
  3055.             end;
  3056.     end;
  3057.  
  3058.  
  3059.     procedure SetErosionDilationCount; {(n:integer)}
  3060.         var
  3061.             n: LongInt;
  3062.     begin
  3063.         GetLeftParen;
  3064.         n := GetInteger;
  3065.         GetRightParen;
  3066.         if (n < 1) or (n > 8) then
  3067.             MacroError('Argument out of range');
  3068.         if Token <> DoneT then begin
  3069.                 BinaryCount := n;
  3070.                 BinaryThreshold := BinaryCount * 255;
  3071.             end;
  3072.     end;
  3073.  
  3074.  
  3075.     procedure SetSliceSpacing; {(n:real)}
  3076.         var
  3077.             n: extended; {pixels}
  3078.     begin
  3079.         GetLeftParen;
  3080.         n := GetExpression;
  3081.         GetRightParen;
  3082.         if (n <= 0.0) or (n > 100.0) then
  3083.             MacroError('Argument out of range');
  3084.         if info^.StackInfo = nil then
  3085.             MacroError('No stack');
  3086.         if Token <> DoneT then
  3087.             info^.StackInfo^.SliceSpacing := n;
  3088.     end;
  3089.  
  3090.  
  3091.     procedure GetOrPutLineOrColumn;  {(x,y,count:integer:integer)}
  3092.         var
  3093.             x, y, count, i: integer;
  3094.             MaskRect: rect;
  3095.             aLine2: LineType;
  3096.     begin
  3097.         GetLeftParen;
  3098.         x := GetInteger;
  3099.         GetComma;
  3100.         y := GetInteger;
  3101.         GetComma;
  3102.         count := GetInteger;
  3103.         GetRightParen;
  3104.         if (Token <> DoneT) and (count <= MaxLine) then
  3105.             with MacrosP^ do begin
  3106.                     KillRoi;
  3107.                     case MacroCommand of
  3108.                         GetRowC: 
  3109.                             GetLine(x, y, count, aLine);
  3110.                         PutRowC:  begin
  3111.                                 PutLine(x, y, count, aLine);
  3112.                                 SetRect(MaskRect, x, y, x + count, y + 1);
  3113.                                 UpdateScreen(MaskRect);
  3114.                                 info^.changes := true;
  3115.                             end;
  3116.                         GetColumnC: 
  3117.                             GetColumn(x, y, count, aLine);
  3118.                         PutColumnC:  begin
  3119.                                 PutColumn(x, y, count, aLine);
  3120.                                 SetRect(MaskRect, x, y, x + 1, y + count);
  3121.                                 UpdateScreen(MaskRect);
  3122.                                 info^.changes := true;
  3123.                             end;
  3124.                     end; {case}
  3125.                 end;
  3126.     end;
  3127.  
  3128.  
  3129.     procedure CheckVersion; {(RequiredVersion:real)}
  3130.         var
  3131.             RequiredVersion: extended;
  3132.             str: str255;
  3133.     begin
  3134.         GetLeftParen;
  3135.         RequiredVersion := GetExpression;
  3136.         GetRightParen;
  3137.         if (Token <> DoneT) then
  3138.             if round(RequiredVersion * 100.0) > version then begin
  3139.                     RealToString(RequiredVersion, 1, 2, str);
  3140.                     PutError(concat('This macro requires version ', str, ' or later of NIH Image.'));
  3141.                     Token := DoneT;
  3142.                 end;
  3143.     end;
  3144.  
  3145.  
  3146.     procedure SetOptions; {(Options:string)}
  3147.         var
  3148.             options: str255;
  3149.             mtype: MeasurementTypes;
  3150.             i, LastOption: integer;
  3151.             SaveMeasurements: SetOfMeasurements;
  3152.     begin
  3153.         GetLeftParen;
  3154.         Options := GetString;
  3155.         GetRightParen;
  3156.         if (Token <> DoneT) then begin
  3157.                 SaveMeasurements := measurements;
  3158.                 MakeLowerCase(options);
  3159.                 Measurements := [];
  3160.                 if pos('area', options) <> 0 then
  3161.                     Measurements := Measurements + [AreaM];
  3162.                 if pos('mean', options) <> 0 then
  3163.                     Measurements := Measurements + [MeanM];
  3164.                 if pos('st', options) <> 0 then
  3165.                     Measurements := Measurements + [StdDevM];
  3166.                 if pos('center', options) <> 0 then
  3167.                     Measurements := Measurements + [xyLocM];
  3168.                 if pos('mode', options) <> 0 then
  3169.                     Measurements := Measurements + [ModeM];
  3170.                 if (pos('per', options) <> 0) or (pos('length', options) <> 0) then
  3171.                     Measurements := Measurements + [LengthM];
  3172.                 if pos('major', options) <> 0 then
  3173.                     Measurements := Measurements + [MajorAxisM];
  3174.                 if pos('minor', options) <> 0 then
  3175.                     Measurements := Measurements + [MinorAxisM];
  3176.                 if pos('angle', options) <> 0 then
  3177.                     Measurements := Measurements + [AngleM];
  3178.                 if pos('int', options) <> 0 then
  3179.                     Measurements := Measurements + [IntDenM];
  3180.                 if pos('max', options) <> 0 then
  3181.                     Measurements := Measurements + [MinMaxM];
  3182.                 if pos('1', options) <> 0 then
  3183.                     Measurements := Measurements + [User1M];
  3184.                 if pos('2', options) <> 0 then
  3185.                     Measurements := Measurements + [User2M];
  3186.                 UpdateFitEllipse;
  3187.                 if Measurements <> SaveMeasurements then
  3188.                     UpdateList;
  3189.             end;
  3190.     end;
  3191.  
  3192.  
  3193.     procedure SetLabel;
  3194.         var
  3195.             SaveCommand: CommandType;
  3196.             str, SaveLabel: str255;
  3197.     begin
  3198.         SaveCommand := MacroCommand;
  3199.         GetArguments(str);
  3200.         TruncateString(str, maxLabelLength);
  3201.         case SaveCommand of
  3202.             SetMajorC:  begin
  3203.                     SaveLabel := MajorLabel;
  3204.                     MajorLabel := str;
  3205.                     Measurements := Measurements + [MajorAxisM];
  3206.                 end;
  3207.             SetMinorC:  begin
  3208.                     SaveLabel := MinorLabel;
  3209.                     MinorLabel := str;
  3210.                     Measurements := Measurements + [MinorAxisM];
  3211.                 end;
  3212.             SetUser1C:  begin
  3213.                     SaveLabel := User1Label;
  3214.                     User1Label := str;
  3215.                     Measurements := Measurements + [User1M];
  3216.                 end;
  3217.             SetUser2C:  begin
  3218.                     SaveLabel := User2Label;
  3219.                     User2Label := str;
  3220.                     Measurements := Measurements + [User2M];
  3221.                 end;
  3222.         end; {case}
  3223.         ShowInfo;
  3224.         if str <> SaveLabel then
  3225.             UpdateList;
  3226.     end;
  3227.  
  3228.  
  3229.     procedure DoUpdateLUT;
  3230.     begin
  3231.         with info^ do begin
  3232.                 LoadLUT(ctable);
  3233.                 IdentityFunction := false;
  3234.                 if isGrayScaleLUT then
  3235.                     LutMode := CustomGrayScale
  3236.                 else begin
  3237.                         SetupPseudocolor;
  3238.                         LutMode := PseudoColor;
  3239.                     end;
  3240.                 UpdateMap;
  3241.             if ScreenDepth<>8 then
  3242.                  UpdatePicWindow;
  3243.             end;
  3244.     end;
  3245.  
  3246.  
  3247.     procedure SubtractBackground; {(Options:string; BallRadius:integer)}
  3248.         var
  3249.             options: str255;
  3250.             radius, item: integer;
  3251.     begin
  3252.         GetLeftParen;
  3253.         Options := GetString;
  3254.         GetComma;
  3255.         radius := GetInteger;
  3256.         GetRightParen;
  3257.         if (Token <> DoneT) then begin
  3258.                 MakeLowerCase(options);
  3259.                 FasterBackgroundSubtraction := pos('faster', options) <> 0;
  3260.                 item := Sub2DItem;
  3261.                 if pos('hor', options) <> 0 then
  3262.                     item := HorizontalItem;
  3263.                 if pos('ver', options) <> 0 then
  3264.                     item := VerticalItem;
  3265.                 if pos('roll', options) <> 0 then
  3266.                     item := Sub2DItem;
  3267.                 if pos('remove', options) <> 0 then
  3268.                     item := RemoveStreaksItem;
  3269.             end;
  3270.         BallRadius := Radius;
  3271.         if Radius < 1 then
  3272.             BallRadius := 1;
  3273.         if Radius > 319 then
  3274.             BallRadius := 319;
  3275.         DoBackgroundMenuEvent(Item);
  3276.     end;
  3277.  
  3278.  
  3279.     procedure SetExportMode;
  3280.         var
  3281.             mode: str255;
  3282.     begin
  3283.         mode := GetStringArg;
  3284.         if Token <> DoneT then begin
  3285.                 MakeLowerCase(mode);
  3286.                 ExportAsWhat := AsRaw;
  3287.                 if pos('mcid', mode) <> 0 then
  3288.                     ExportAsWhat := asMCID;
  3289.                 if pos('text', mode) <> 0 then
  3290.                     ExportAsWhat := asText;
  3291.                 if pos('lut', mode) <> 0 then
  3292.                     ExportAsWhat := asLUT;
  3293.                 if pos('meas', mode) <> 0 then
  3294.                     ExportAsWhat := asMeasurements;
  3295.                 if pos('plot', mode) <> 0 then
  3296.                     ExportAsWhat := asPlotValues;
  3297.                 if pos('hist', mode) <> 0 then
  3298.                     ExportAsWhat := asHistogramValues;
  3299.                 if pos('xy', mode) <> 0 then
  3300.                     ExportAsWhat := asCoordinates;
  3301.             end;
  3302.     end;
  3303.  
  3304.  
  3305.     procedure SetSaveAsMode;
  3306.         var
  3307.             mode: str255;
  3308.     begin
  3309.         mode := GetStringArg;
  3310.         if Token <> DoneT then begin
  3311.                 MakeLowerCase(mode);
  3312.                 SaveAsWhat := asTiff;
  3313.                 if pos('tiff', mode) <> 0 then
  3314.                     SaveAsWhat := asTiff;
  3315.                 if pos('pict', mode) <> 0 then
  3316.                     SaveAsWhat := asPict;
  3317.                 if pos('paint', mode) <> 0 then
  3318.                     SaveAsWhat := asMacPaint;
  3319.                 if pos('pics', mode) <> 0 then
  3320.                     SaveAsWhat := asPICS;
  3321.                 if pos('lut', mode) <> 0 then
  3322.                     SaveAsWhat := AsPalette;
  3323.                 if pos('outline', mode) <> 0 then
  3324.                     SaveAsWhat := AsOutline;
  3325.                 if pos('rgb', mode) <> 0 then with info^ do begin
  3326.                     if StackInfo = nil then begin
  3327.                         MacroError('Stack required');
  3328.                         exit(SetSaveAsMode);
  3329.                     end;
  3330.                     if StackInfo^.nSlices <> 3 then begin
  3331.                         MacroError('Stack must have 3 slices');
  3332.                         exit(SetSaveAsMode);
  3333.                     end;
  3334.                     StackInfo^.StackType := rgbStack;
  3335.                     UpdateTitleBar;
  3336.                 end;
  3337.             end;
  3338.     end;
  3339.  
  3340.  
  3341.     procedure MoveCurrentWindow;{(x,y:integer)}
  3342.         var
  3343.             x, y: integer;
  3344.             ignore: integer;
  3345.             fwptr: WindowPtr;
  3346.             kind: integer;
  3347.     begin
  3348.         GetLeftParen;
  3349.         x := GetInteger;
  3350.         GetComma;
  3351.         y := GetInteger;
  3352.         GetRightParen;
  3353.         fwptr := FrontWindow;
  3354.         if fwptr <> nil then begin
  3355.                 kind := WindowPeek(fwptr)^.WindowKind;
  3356.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  3357.                     MoveWindow(fwptr, x, y, true);
  3358.             end;
  3359.     end;
  3360.  
  3361.  
  3362.     procedure DoUserCode; {str:str255; Param1,Param2,Param3:real;}
  3363.   {Contributed by Mark Vivino}
  3364.         var
  3365.             WhichCode: integer;
  3366.             Param1, Param2, Param3: extended;
  3367.             str: str255;
  3368.             NewVersion: boolean;
  3369.     begin
  3370.         GetLeftParen;
  3371.         GetToken;
  3372.         NewVersion := (token = StringLiteral) or (token = StringVariable);
  3373.         PutTokenBack;
  3374.         WhichCode := 0;
  3375.         str := '';
  3376.         if NewVersion then
  3377.             str := GetString
  3378.         else
  3379.             WhichCode := GetInteger;
  3380.         GetComma;
  3381.         Param1 := GetExpression;
  3382.         GetComma;
  3383.         Param2 := GetExpression;
  3384.         GetComma;
  3385.         Param3 := GetExpression;
  3386.         GetRightParen;
  3387.         if Token <> DoneT then begin
  3388.                 if NewVersion then
  3389.                     UserMacroCode(str, Param1, Param2, Param3)
  3390.                 else begin
  3391.                         if (WhichCode < 1) or (WhichCode > 10) then
  3392.                             MacroError('Range error . Allowable range is 1 to 10.');
  3393.                         OldUserMacroCode(WhichCode, Param1, Param2, Param3);
  3394.                     end;
  3395.             end;
  3396.     end;
  3397.  
  3398.  
  3399.     procedure CloseSerialPorts;
  3400.         var
  3401.             err: OSErr;
  3402.     begin
  3403.         if SerialBufferP <> nil then begin
  3404.                 err := CloseDriver(SerialOut);
  3405.                 err := CloseDriver(SerialIn);
  3406.                 DisposePtr(SerialBufferP);
  3407.             end;
  3408.     end;
  3409.  
  3410.  
  3411.     procedure OpenSerial;
  3412.         const
  3413.             SerialBufferSize = 1024;
  3414.         var
  3415.             err: OSErr;
  3416.             baud, data, stop, parity, i: integer;
  3417.             config: integer;
  3418.             flags: SerShk;
  3419.             str: str255;
  3420.     begin
  3421.         CloseSerialPorts;
  3422.         baud := baud9600;
  3423.         data := data8;
  3424.         stop := stop10;
  3425.         parity := noParity;
  3426.         str := GetStringArg;
  3427.         if token = DoneT then
  3428.             exit(OpenSerial);
  3429.         MakeLowerCase(str);
  3430.         if pos('300', str) <> 0 then
  3431.             baud := baud300;
  3432.         if pos('1200', str) <> 0 then
  3433.             baud := baud1200;
  3434.         if pos('2400', str) <> 0 then
  3435.             baud := baud2400;
  3436.         if pos('19200', str) <> 0 then
  3437.             baud := baud19200;
  3438.         if pos('two', str) <> 0 then
  3439.             stop := stop20;
  3440.         if pos('seven', str) <> 0 then
  3441.             data := data7;
  3442.         i:=pos('even', str);
  3443.         if (i <> 0) and (str[i-1]<>'s') then
  3444.             parity := evenParity;
  3445.         if pos('odd', str) <> 0 then
  3446.             parity := oddParity;
  3447.         if (OpenDriver('.AOut', SerialOut) <> NoErr) or (OpenDriver('.AIn', SerialIn) <> NoErr) then begin
  3448.                 MacroError('Error opening modem port');
  3449.                 exit(OpenSerial);
  3450.             end;
  3451.         SerialBufferP := NewPtr(SerialBufferSize);
  3452.         if SerialBufferP = nil then begin
  3453.                 MacroError('Out of Memory');
  3454.                 exit(OpenSerial);
  3455.             end;
  3456.         with flags do begin
  3457.                 fXOn := ord(false); {Disable xon/xoff output flow control}
  3458.                 fCTS := ord(false); {Disable CTS (output) flow control}
  3459.                 xOn := chr(17);
  3460.                 xOff := chr(19);
  3461.                 errs := 0;
  3462.                 evts := 0;
  3463.                 fInX := ord(true);  {Enable xon/xoff input flow control}
  3464.                 fDTR := ord(true); {Enable DTR (input) flow control}
  3465.             end;
  3466.         Config := baud + data + stop + parity;
  3467.         Err := SerHShake(SerialOut, flags);
  3468.         Err := SerSetBuf(SerialIn, SerialBufferP, SerialBufferSize);
  3469.         Err := SerReset(SerialOut, Config);
  3470.     end;
  3471.  
  3472.  
  3473.     procedure PutSerial;
  3474.         var
  3475.             i: integer;
  3476.             Size: LongInt;
  3477.             OutputBuffer: packed array[1..256] of char;
  3478.             str: str255;
  3479.             err: OSErr;
  3480.     begin
  3481.         GetArguments(str);
  3482.         if token = DoneT then
  3483.             exit(PutSerial);
  3484.         if SerialBufferP = nil then begin
  3485.                 MacroError('Serial port not open');
  3486.                 exit(PutSerial);
  3487.             end;
  3488.         Size := 0;
  3489.         for i := 1 to length(str) do begin
  3490.                 size := size + 1;
  3491.                 OutputBuffer[size] := str[i];
  3492.             end;
  3493.         if size > 0 then
  3494.             err := fswrite(SerialOut, size, @OutputBuffer);
  3495.     end;
  3496.  
  3497.  
  3498.     procedure DoSetCursor; {str: string}
  3499.         var
  3500.             str: str255;
  3501.     begin
  3502.         str := GetStringArg;
  3503.         if Token <> DoneT then begin
  3504.                 MakeLowerCase(str);
  3505.                 if pos('watch', str) <> 0 then
  3506.                     SetCursor(watch);
  3507.                 if pos('cross', str) <> 0 then
  3508.                     SetCursor(ToolCursor[SelectionTool]);
  3509.                 if pos('arrow', str) <> 0 then
  3510.                     InitCursor;
  3511.                 if pos('finger', str) <> 0 then
  3512.                     SetCursor(FingerCursor);
  3513.             end;
  3514.     end;
  3515.  
  3516.  
  3517.     procedure SetVideoOptions; {options: string[, gain:integer, offset:integer]}
  3518.         var
  3519.             options: str255;
  3520.             NewSyncMode: SyncModeType;
  3521.       gain, offset: integer;
  3522.  
  3523.         procedure SetOption (id: integer; var option: boolean; enable: boolean);
  3524.     {Updates the modeless Video Control dialog box.}
  3525.         begin
  3526.             if option <> enable then
  3527.                 DoVideoControl(id)
  3528.         end;
  3529.  
  3530.     begin
  3531.         GetLeftParen;
  3532.         options := GetString;
  3533.         GetToken;
  3534.         if token = comma then begin
  3535.             gain := GetInteger;
  3536.             GetComma;
  3537.             offset := GetInteger
  3538.         end
  3539.         else begin
  3540.             PutTokenBack;
  3541.             gain := 255 - (DacHigh - DacLow);
  3542.             offset := DacLow;
  3543.         end;
  3544.         GetRightParen;
  3545.         if Token <> DoneT then begin
  3546.                 MakeLowerCase(options);
  3547.                 SetOption(InvertID, InvertVideo, pos('invert', options) <> 0);
  3548.                 SetOption(HighlightID, HighlightSaturatedPixels, pos('high', options) <> 0);
  3549.                 SetOption(TriggerID, ExternalTrigger, pos('trig', options) <> 0);
  3550.                 if pos('sep', options) <> 0 then
  3551.                     NewSyncMode := SeparateSync
  3552.                 else
  3553.                     NewSyncMode := NormalSync;
  3554.                 if NewSyncMode <> SyncMode then
  3555.                     DoVideoControl(SyncID);
  3556.                 SetOffset(offset, gain);
  3557.                 SetGain(offset, gain);
  3558.                 if VideoControl <> nil then begin
  3559.                     gain := 255 - (DacHigh - DacLow);
  3560.                     ShowOffsetAndGain(DacLow, gain);
  3561.                 end;
  3562.                 OscillatingMovies := pos('osc', options) <> 0;
  3563.                 BlindMovieCapture := pos('blind', options) <>0;
  3564.                 if (FrameGrabber = ScionLG3) or (FrameGrabber=ScionAG5) or (FrameGrabber=ScionVG5f) then begin
  3565.                         DacLowReg^ := DacLow;
  3566.                         DacHighReg^ := DacHigh;
  3567.                     end;
  3568.             end;
  3569.     end;
  3570.  
  3571.  
  3572.     procedure SetChannel; {(channel:integer)}
  3573.         var
  3574.             channel: integer;
  3575.     begin
  3576.         GetLeftParen;
  3577.         channel := GetInteger;
  3578.         GetRightParen;
  3579.         if (channel < 1) or (channel > 4) then
  3580.             MacroError('Bad channel number')
  3581.         else
  3582.             DoVideoControl(FirstChannelID + channel - 1);
  3583.     end;
  3584.  
  3585.  
  3586.     procedure DoAcquire;
  3587.         var
  3588.             fname: str255;
  3589.     begin
  3590.         fname := GetStringArg;
  3591.         LoadAcqPlugIn(fname);
  3592.     end;
  3593.  
  3594.  
  3595.     procedure CallExportPlugin;
  3596.         var
  3597.             fname: str255;
  3598.     begin
  3599.         fname := GetStringArg;
  3600.         LoadExportPlugIn(fname);
  3601.     end;
  3602.  
  3603.  
  3604.     procedure CallFilterPlugin;
  3605.         var
  3606.             fname: str255;
  3607.     begin
  3608.         fname := GetStringArg;
  3609.         LoadFilterPlugIn(fname);
  3610.     end;
  3611.  
  3612.  
  3613.     procedure DoPhotoMode;
  3614.         var
  3615.             erase: boolean;
  3616.     begin
  3617.         erase := GetBooleanArg;
  3618.         if Token <> DoneT then begin
  3619.                 if erase then begin
  3620.                         EraseScreen;
  3621.                         UpdatePicWindow;
  3622.                         InPhotoMode := true;
  3623.                     end
  3624.                 else if InPhotoMode then
  3625.                         RestoreScreen;
  3626.             end;
  3627.     end;
  3628.  
  3629.  
  3630.     procedure RGBToIndexed; {options: string}
  3631.         var
  3632.             options: str255;
  3633.     begin
  3634.         options := GetStringArg;
  3635.         if Token <> DoneT then begin
  3636.                 MakeLowerCase(options);
  3637.                 RGBLut := CustomLUT;
  3638.                 DitherColor := false;
  3639.                 if pos('exist', options) <> 0 then
  3640.                     RGBLut := ExistingLUT;
  3641.                 if pos('system', options) <> 0 then
  3642.                     RGBLut := SystemLUT;
  3643.                 if pos('dither', options) <> 0 then
  3644.                     DitherColor := true;
  3645.                 ConvertRGBToEightBitColor(false);
  3646.             end;
  3647.     end;
  3648.  
  3649.  
  3650.  procedure DoAverageFrames; {[(Options:string; nFrames:integer)]}
  3651.   var
  3652.    options: str255;
  3653.    nFrames: LongInt;
  3654.    HasArguments,ShowDialog,okay: boolean;
  3655.  begin
  3656.   GetToken;
  3657.   HasArguments := token = LeftParen;
  3658.   PutTokenBack;
  3659.   ShowDialog:=false;
  3660.   if HasArguments then begin
  3661.     GetLeftParen;
  3662.     Options := GetString;
  3663.     GetComma;
  3664.     nFrames := GetInteger;
  3665.     ShowDialog:= nFrames <= 0;
  3666.     if not ShowDialog then
  3667.         FramesToAverage := nFrames;
  3668.     GetRightParen;
  3669.     if (Token <> DoneT) then begin
  3670.       MakeLowerCase(options);
  3671.       VideoRateAveraging := false;
  3672.       SumFrames := false;
  3673.       IntegrateOnChip := false;
  3674.       if (pos('int', options) <> 0) or (pos('sum', options) <> 0) then
  3675.        sumFrames := true;
  3676.       if pos('video', options) <> 0 then
  3677.        VideoRateAveraging := true;
  3678.       if (pos('camera', options) <> 0) or (pos('chip', options) <> 0) then begin
  3679.        if  (FrameGrabber<>ScionLG3) and (FrameGrabber<>ScionAG5) and (FrameGrabber<>ScionVG5f) then begin
  3680.          MacroError('On-chip integration requires a Scion frame grabber.');
  3681.          exit(DoAverageFrames)
  3682.        end;
  3683.        VideoRateAveraging := false;
  3684.        SumFrames := false;
  3685.        IntegrateOnChip := true;
  3686.        end;
  3687.      end;
  3688.    end; {has arguments}
  3689.   if token <> DoneT then begin
  3690.    if ShowDialog
  3691.     then okay:=DoAveragingOptions
  3692.     else okay:=true;
  3693.    if okay then AverageFrames;
  3694.   end;
  3695.  end;
  3696.  
  3697.  
  3698.     procedure DoSelectWindow;{('str')}
  3699.         var
  3700.             str, wTitle: str255;
  3701.             WPeek, NextWPeek: WindowPeek;
  3702.             id: integer;
  3703.             TempInfo: InfoPtr;
  3704.     begin
  3705.         GetArguments(str);
  3706.         MakeLowerCase(str);
  3707.         if Token <> DoneT then begin
  3708.                 wPeek := WindowPeek(FrontWindow);
  3709.                 while wPeek <> nil do begin
  3710.                         NextWPeek := wPeek^.NextWindow;
  3711.                         if wPeek^.WindowKind = PicKind then begin
  3712.                                 TempInfo := InfoPtr(wPeek^.RefCon);
  3713.                                 wTitle := TempInfo^.title;
  3714.                             end
  3715.                         else
  3716.                             wTitle := wPeek^.TitleHandle^^;
  3717.                         MakeLowerCase(wTitle);
  3718.                         if str = wTitle then begin
  3719.                                 if wPeek^.WindowKind = PicKind then begin
  3720.                                         info := InfoPtr(wPeek^.RefCon);
  3721.                                         with info^ do
  3722.                                             if (PicNum >= 1) and (PicNum <= nPics) then
  3723.                                                 SelectImage(PicNum);
  3724.                                     end
  3725.                                 else
  3726.                                     SelectWindow(WindowPtr(wPeek));
  3727.                                 leave;
  3728.                             end;
  3729.                         wpeek := NextWPeek;
  3730.                     end;
  3731.                 if wPeek = nil then
  3732.                     MacroError('Window not found');
  3733.             end;
  3734.     end;
  3735.  
  3736.  
  3737.     procedure GetThreshold;  {(lower,upper)}
  3738.         var
  3739.             loc1, loc2: integer;
  3740.     begin
  3741.         GetLeftParen;
  3742.         loc1 := GetVar;
  3743.         GetComma;
  3744.         loc2 := GetVar;
  3745.         GetRightParen;
  3746.         if Token <> DoneT then
  3747.             with MacrosP^ do
  3748.                 with info^ do begin
  3749.                         if Thresholding then begin
  3750.                                 stack[loc1].value := ColorStart;
  3751.                                 stack[loc2].value := 255;
  3752.                             end
  3753.                         else if DensitySlicing then begin
  3754.                                 stack[loc1].value := SliceStart;
  3755.                                 stack[loc2].value := SliceEnd;
  3756.                             end
  3757.                         else begin
  3758.                                 stack[loc1].value := 0;
  3759.                                 stack[loc2].value := 0;
  3760.                             end;
  3761.                     end;
  3762.     end;
  3763.  
  3764.  
  3765.     procedure SortPalette;
  3766.         type
  3767.             MyHSVColor = record
  3768.                     lHue, lSaturation, lValue: LongInt;
  3769.                 end;
  3770.             HSVRec = record
  3771.                     index: integer;
  3772.                     hsv: MyHSVColor;
  3773.                 end;
  3774.             HSVArrayType = array[0..255] of HSVRec;
  3775.         var
  3776.             TempTable: MyCSpecArray;
  3777.             i: integer;
  3778.             HSVArray: HSVArrayType;
  3779.             h, s, v: LongInt;
  3780.             fHue, fSaturation, fValue: fixed;
  3781.             TempHSV: HSVColor;
  3782.             table: LookupTable;
  3783.  
  3784.         procedure SortByHue;
  3785.     {Selection sorts from "Algorithms" by Robert Sedgewick.}
  3786.             var
  3787.                 i, j, min: integer;
  3788.                 t: HSVRec;
  3789.         begin
  3790.             for i := 1 to 254 do begin
  3791.                     min := i;
  3792.                     for j := i + 1 to 254 do
  3793.                         if HSVArray[j].hsv.lHue < HSVArray[min].hsv.lHue then
  3794.                             min := j;
  3795.                     t := HSVArray[min];
  3796.                     HSVArray[min] := HSVArray[i];
  3797.                     HSVArray[i] := t;
  3798.                 end;
  3799.         end;
  3800.  
  3801.     begin
  3802.         ShowWatch;
  3803.         DisableDensitySlice;
  3804.         with info^ do begin
  3805.                 for i := 1 to 254 do begin
  3806.                         HSVArray[i].index := i;
  3807.                         rgb2hsv(cTable[i].rgb, TempHSV);
  3808.                         with TempHSV do begin
  3809.                                 fHue := SmallFract2Fix(hue);
  3810.                                 fSaturation := SmallFract2Fix(saturation);
  3811.                                 fValue := SmallFract2Fix(value);
  3812.                             end;
  3813.                         with HSVArray[i].hsv do begin
  3814.                                 lHue := ord4(band(fHue, $ffff));
  3815.                                 lSaturation := ord4(band(fSaturation, $ffff));
  3816.                                 lValue := ord4(band(fValue, $ffff));
  3817.                             end;
  3818.                     end;
  3819.                 SortByHue;
  3820.                 for i := 1 to 254 do
  3821.                     TempTable[i].rgb := cTable[HSVArray[i].index].rgb;
  3822.                 cTable := TempTable;
  3823.                 LoadLUT(cTable);
  3824.                 if info <> NoInfo then begin
  3825.                         table[0] := 0;
  3826.                         table[255] := 255;
  3827.                         for i := 1 to 254 do
  3828.                             table[HSVArray[i].index] := i;
  3829.                         ApplyTable(table);
  3830.                     end;
  3831.                 WhatToUndo := NothingToUndo;
  3832.                 SetupPseudocolor;
  3833.                 ColorTable := CustomTable;
  3834.             end; {with}
  3835.     end;
  3836.  
  3837.  
  3838.     procedure DoProject;
  3839.     begin
  3840.         if info^.StackInfo = nil then begin
  3841.             MacroError('Stack required');
  3842.             exit(DoProject);
  3843.         end;
  3844.         if not ((ProjectC in RoutinesCalled) or (SetProjectionC in RoutinesCalled)) then begin
  3845.                 if ShowProjectDialogBox then
  3846.                     DoProjection
  3847.                 else
  3848.                     token := DoneT;
  3849.             end
  3850.         else with info^.StackInfo^ do begin
  3851.             if SliceSpacing <= 0.0 then
  3852.                 SliceSpacing := 1.0;
  3853.             if DensitySlicing then
  3854.                 with info^ do begin
  3855.                         TransparencyLower := SliceStart;
  3856.                         TransparencyUpper := SliceEnd;
  3857.                     end;
  3858.             DoProjection;
  3859.         end;
  3860.         RoutinesCalled := RoutinesCalled + [ProjectC];
  3861.     end;
  3862.  
  3863.  
  3864.     procedure DoNewTextWindow; {(name,width,height)}
  3865.         var
  3866.             str: str255;
  3867.             okay, OptionalArguments: boolean;
  3868.             width, height: LongInt;
  3869.     begin
  3870.         GetLeftParen;
  3871.         str := GetString;
  3872.         GetToken;
  3873.         OptionalArguments := token <> RightParen;
  3874.         PutTokenBack;
  3875.         width := 500;
  3876.         height := 400;
  3877.         if OptionalArguments then begin
  3878.                 GetComma;
  3879.                 width := GetInteger;
  3880.                 if width < 8 then
  3881.                     width := 8;
  3882.                 GetComma;
  3883.                 height := GetInteger;
  3884.                 if height < 8 then
  3885.                     height := 8;
  3886.             end;
  3887.         GetRightParen;
  3888.         if Token <> DoneT then
  3889.             okay := MakeNewTextWindow(str, width, height);
  3890.     end;
  3891.  
  3892.  
  3893.     procedure ImageMath; {('op',pic1,pic2,gain,offset,'result')}
  3894.         var
  3895.             op, result: str255;
  3896.             pic1, pic2, DstPidNum: LongInt;
  3897.             gain, offset: extended;
  3898.             roi:rect;
  3899.             DstInfo:InfoPtr;
  3900.             isPidNum:boolean;
  3901.     begin
  3902.         GetLeftParen;
  3903.         op := GetString;
  3904.         GetComma;
  3905.         pic1 := GetInteger;
  3906.         GetComma;
  3907.         pic2 := GetInteger;
  3908.         GetComma;
  3909.         gain := GetExpression;
  3910.         GetComma;
  3911.         offset := GetExpression;
  3912.         GetComma;
  3913.         GetToken;
  3914.         isPidNum:=token=variable;
  3915.         PutTokenBack;
  3916.         if isPidNum
  3917.             then DstPidNum:=GetInteger
  3918.             else result := GetString;
  3919.         GetRightParen;
  3920.         if token <> DoneT then begin
  3921.                 MakeLowerCase(op);
  3922.                 RealImageMath:=false;
  3923.                 if pos('calibrate', op) <> 0 then
  3924.                     RealImageMath := true;
  3925.                 if pos('real', op) <> 0 then
  3926.                     RealImageMath := true;
  3927.                 if pos('add', op) <> 0 then
  3928.                     CurrentMathOp := AddMath;
  3929.                 if pos('sub', op) <> 0 then
  3930.                     CurrentMathOp := SubMath;
  3931.                 if pos('mul', op) <> 0 then
  3932.                     CurrentMathOp := MulMath;
  3933.                 if (pos('cmul', op) <> 0) or (pos('conjugate', op) <> 0) then begin
  3934.                     CurrentMathOp := cMulMath;
  3935.                     RealImageMath := true;
  3936.                 end;
  3937.                 if pos('div', op) <> 0 then
  3938.                     CurrentMathOp := DivMath;
  3939.                 if pos('and', op) <> 0 then
  3940.                     CurrentMathOp := AndMath;
  3941.                 if pos('or', op) <> 0 then
  3942.                     CurrentMathOp := OrMath;
  3943.                 if pos('xor', op) <> 0 then
  3944.                     CurrentMathOp := XorMath;
  3945.                 if pos('max', op) <> 0 then
  3946.                     CurrentMathOp := MaxMath;
  3947.                 if pos('min', op) <> 0 then
  3948.                     CurrentMathOp := MinMath;
  3949.                 if pos('copy', op) <> 0 then
  3950.                     CurrentMathOp := CopyMath;
  3951.                 MathGain := gain;
  3952.                 MathOffset := offset;
  3953.                 if not GetMathRoi(pic1, pic2, roi) then
  3954.                     exit(ImageMath);
  3955.                 if isPidNum then begin
  3956.                     DstInfo := GetInfoPtr(DstPidNum);
  3957.                     if DstInfo=nil then begin
  3958.                         MacroError('Bad pid number');
  3959.                         exit(ImageMath);
  3960.                     end;
  3961.                     if RealImageMath and (DstInfo^.dataH = nil) then begin
  3962.                         MacroError('Real output image required');
  3963.                         exit(ImageMath);
  3964.                     end;
  3965.                     SelectWindow(DstInfo^.wptr);
  3966.                     Info := DstInfo;
  3967.                     ActivateWindow;
  3968.                     LoadLUT(info^.cTable);
  3969.                     UpdatePicWindow;
  3970.                     KillRoi;
  3971.                 end else begin
  3972.                     with roi do
  3973.                         if RealImageMath then begin
  3974.                             if not NewRealWindow(result, right-left, bottom-top) then
  3975.                                 exit(ImageMath)
  3976.                         end else begin
  3977.                             if not NewPicWindow(result, right-left, bottom-top) then
  3978.                                 exit(ImageMath)
  3979.                         end;
  3980.                     DstInfo := Info;
  3981.                 end;
  3982.                 DoMath(pic1, pic2, DstInfo, roi);
  3983.             end;
  3984.     end;
  3985.  
  3986.  
  3987.     procedure PasteLive;
  3988.     begin
  3989.         with info^ do begin
  3990.                 if not RoiShowing or (RoiType <> RectRoi) then begin
  3991.                         MacroError('No selection');
  3992.                         exit(PasteLive);
  3993.                     end;
  3994.                 if PictureType = FrameGrabberType then begin
  3995.                         MacroError('Can''t paste into Camera window');
  3996.                         exit(PasteLive);
  3997.                     end;
  3998.                 if FrameGrabber = NoFrameGrabber then begin
  3999.                         MacroError('No frame grabber');
  4000.                         exit(PasteLive);
  4001.                     end;
  4002.                 if (RoiRect.right > fgwidth) or (RoiRect.bottom > fgheight) then begin
  4003.                         MacroError('Selection out of range');
  4004.                         exit(PasteLive);
  4005.                     end;
  4006.                 SetupUndo;
  4007.                 WhatToUndo := UndoPaste;
  4008.                 ClipBufInfo^.RoiRect := RoiRect;
  4009.                 OpPending := true;
  4010.                 CurrentOp := PasteOp;
  4011.                 LivePasteMode := true;
  4012.                 WhatsOnClip := LivePic;
  4013.             end;{with}
  4014.     end;
  4015.  
  4016.  
  4017.     procedure GetPlotData;  {(var nValues,PixelsPerValue, Min,Max:real)}
  4018.         var
  4019.             loc1, loc2, loc3, loc4: integer;
  4020.     begin
  4021.         GetLeftParen;
  4022.         loc1 := GetVar;
  4023.         GetComma;
  4024.         loc2 := GetVar;
  4025.         GetComma;
  4026.         loc3 := GetVar;
  4027.         GetComma;
  4028.         loc4 := GetVar;
  4029.         GetRightParen;
  4030.         if Token <> DoneT then
  4031.             with MacrosP^, results do begin
  4032.                     ShowPlot := false;
  4033.                     PlotDensityProfile;
  4034.                     ShowPlot := true;
  4035.                     stack[loc1].value := PlotCount;
  4036.                     stack[loc2].value := PlotAvg;
  4037.                     stack[loc3].value := ActualPlotMin;
  4038.                     stack[loc4].value := ActualPlotMax;
  4039.                 end;
  4040.     end;
  4041.  
  4042.  
  4043.     procedure DoDelete;  {(var dest; index, count:integer)}
  4044.         var
  4045.             StackLoc, index, count: integer;
  4046.             str: str255;
  4047.     begin
  4048.         GetLeftParen;
  4049.         StackLoc := GetStringVar;
  4050.         str := TokenStr;
  4051.         GetComma;
  4052.         index := GetInteger;
  4053.         GetComma;
  4054.         count := GetInteger;
  4055.         GetRightParen;
  4056.         if Token <> DoneT then
  4057.             with MacrosP^.stack[StackLoc] do begin
  4058.                     delete(str, index, count);
  4059.                     if StringH <> nil then
  4060.                         StringH^^ := str;
  4061.                 end;
  4062.     end;
  4063.  
  4064.  
  4065.     procedure DoAutoOutline;  {(x,y:integer)}
  4066.         var
  4067.             x, y: integer;
  4068.             start: point;
  4069.     begin
  4070.         GetLeftParen;
  4071.         x := GetInteger;
  4072.         GetComma;
  4073.         y := GetInteger;
  4074.         GetRightParen;
  4075.         if Token <> DoneT then begin
  4076.                 start.h := x;
  4077.                 start.v := y;
  4078.                 AutoOutline(start);
  4079.             end;
  4080.     end;
  4081.  
  4082.  
  4083.     procedure DoFilter; {(fType:string)}
  4084.         var
  4085.             fType: str255;
  4086.             doMore:boolean;
  4087.             t:FateTable;
  4088.     begin
  4089.         GetLeftParen;
  4090.         fType := GetString;
  4091.         GetRightParen;
  4092.         if token <> DoneT then begin
  4093.                 MakeLowerCase(fType);
  4094.                 doMore:=pos('more', fType) <> 0;
  4095.                 if pos('smooth', fType) <> 0 then begin
  4096.                     if doMore then
  4097.                         Filter(UnweightedAvg, 0, t)
  4098.                     else
  4099.                         Filter(WeightedAvg, 0, t);
  4100.                     exit(DoFilter);
  4101.                 end;
  4102.                 if pos('sharpen', fType) <> 0 then begin
  4103.                     if doMore then
  4104.                         Filter(SharpenMore, 0, t)
  4105.                     else
  4106.                         Filter(fsharpen, 0, t);
  4107.                     exit(DoFilter);
  4108.                 end;
  4109.                 if pos('median', fType) <> 0 then begin
  4110.                     RankFilter := MedianRank;
  4111.                     DoRankFilter;
  4112.                     exit(DoFilter);
  4113.                 end;
  4114.                 if (pos('edges', fType) <> 0) or (pos('sobel', fType)<>0) then begin
  4115.                     Filter(FindEdges, 0, t);
  4116.                     exit(DoFilter);
  4117.                 end;
  4118.                 if pos('dither', fType) <> 0 then begin
  4119.                     Filter(Dither, 0, t);
  4120.                     exit(DoFilter);
  4121.                 end;
  4122.                 if pos('min', fType) <> 0 then begin
  4123.                     RankFilter := MinRank;
  4124.                     DoRankFilter;
  4125.                     exit(DoFilter);
  4126.                 end;
  4127.                 if pos('max', fType) <> 0 then begin
  4128.                     RankFilter := MaxRank;
  4129.                     DoRankFilter;
  4130.                     exit(DoFilter);
  4131.                 end;
  4132.                 MacroError('Undefined filter');
  4133.             end;
  4134.     end;
  4135.  
  4136.  
  4137.     procedure DoShadow; {[(Direction:string)]}
  4138.         var
  4139.             direction: str255;
  4140.             t: FateTable;
  4141.     begin
  4142.         GetToken;
  4143.         if token =LeftParen then begin
  4144.             direction := GetString;
  4145.             MakeLowerCase(direction);
  4146.             GetRightParen;
  4147.         end else begin
  4148.             PutTokenBack;
  4149.             direction:='se';
  4150.         end;
  4151.         if Token <> DoneT then
  4152.         if direction='n' then Filter(ShadowN, 0, t)
  4153.         else if direction='ne' then Filter(ShadowNE, 0, t)
  4154.         else if direction='e'  then Filter(ShadowE, 0, t)
  4155.         else if direction='se' then Filter(ShadowSE, 0, t)
  4156.         else if direction='s'  then Filter(ShadowS, 0, t)
  4157.         else if direction='sw' then Filter(ShadowSW, 0, t)
  4158.         else if direction='w'  then Filter(ShadowW, 0, t)
  4159.         else if direction='nw' then Filter(ShadowNW, 0, t)
  4160.         else MacroError('Invalid direction');
  4161.         end;
  4162.  
  4163.  
  4164.     procedure DoCalibrate; {(fit,unit:string,m1,k1,m2,k2,...)}
  4165.         var
  4166.             sFit, sUnit: str255;
  4167.             Measured, Known:StandardsArray;
  4168.             nPairs, i:integer;
  4169.     begin
  4170.         GetLeftParen;
  4171.         sFit := GetString;
  4172.         if token <> DoneT then with info^ do begin
  4173.                 MakeLowerCase(sFit);
  4174.                 if pos('straight', sFit) <> 0 then fit:=StraightLine
  4175.                 else if pos('rodbard', sFit) <> 0 then fit:=RodbardFit
  4176.                 else if pos('od', sFit) <> 0 then fit:=UncalibratedOD
  4177.                 else if pos('uncal', sFit) <> 0 then fit:=Uncalibrated
  4178.                 else if pos('exp', sFit) <> 0 then fit:=ExpoFit
  4179.                 else if pos('log', sFit) <> 0 then fit:=LogFit
  4180.                 else if pos('pow', sFit) <> 0 then fit:=PowerFit
  4181.                 else if pos('poly2', sFit) <> 0 then fit:=Poly2
  4182.                 else if pos('poly3', sFit) <> 0 then fit:=Poly3
  4183.                 else if pos('poly4', sFit) <> 0 then fit:=Poly4
  4184.                 else if pos('poly5', sFit) <> 0 then fit:=Poly5
  4185.                 else begin
  4186.                     MacroError('Unknown fit');
  4187.                     exit(DoCalibrate);
  4188.                 end;
  4189.                 if (fit=Uncalibrated) or (fit=UncalibratedOD) then begin
  4190.                     GetRightParen;
  4191.                     Calibrate;
  4192.                     exit(DoCalibrate);
  4193.                 end;
  4194.         end;
  4195.         GetComma;
  4196.         sUnit := GetString;
  4197.         GetComma;
  4198.         nPairs:=0;
  4199.         GetToken;
  4200.         while (token<>RightParen) and (token<>DoneT) do begin
  4201.             PutTokenBack;
  4202.             if nPairs<MaxStandards then
  4203.                 nPairs:=nPairs+1;
  4204.             Measured[nPairs]:=GetExpression;
  4205.             GetComma;
  4206.             Known[nPairs]:=GetExpression;
  4207.             GetToken;
  4208.             if token=comma then
  4209.                 GetToken;
  4210.         end;
  4211.         if token <> DoneT then with info^ do begin
  4212.                 if nPairs<2 then begin
  4213.                     MacroError('More arguments expected');
  4214.                     exit(DoCalibrate);
  4215.                 end;
  4216.                 TruncateString(sUnit, maxUM);
  4217.                 UnitOfMeasure:=sUnit;
  4218.                 nStandards:=nPairs;
  4219.                 nKnownValues:=nPairs;
  4220.                 for i:=1 to nStandards do begin
  4221.                     ClearResults(i);
  4222.                     uMean[i]:=Measured[i];
  4223.                     Mean^[i]:=Measured[i];
  4224.                     StandardValues[i]:=Known[i];
  4225.                 end;
  4226.                 mCount := nStandards;
  4227.                 UpdateList;
  4228.                 Calibrate;
  4229.             end;
  4230.     end;
  4231.  
  4232.  
  4233.     procedure DoMakeMovie; {(Options:string; nFrames:integer; delay:extended)}
  4234.         var
  4235.             options: str255;
  4236.             nFrames: integer;
  4237.             delay: extended;
  4238.             ShowDialog: boolean;
  4239.     begin
  4240.             GetLeftParen;
  4241.             Options := GetString;
  4242.             GetComma;
  4243.             nFrames := GetInteger;
  4244.             GetComma;
  4245.             delay := GetExpression;
  4246.             GetRightParen;
  4247.             if (Token <> DoneT) then begin
  4248.                     ShowDialog := pos('dialog', options) <> 0;
  4249.                     if ShowDialog and (length(options) = 6) then begin
  4250.                         MakeMovie(true);
  4251.                         exit(DoMakeMovie);
  4252.                     end;
  4253.                     if nFrames > 0 then
  4254.                         FramesWanted := nFrames;
  4255.                     if delay >= 0.0 then
  4256.                         SecondsPerFrame := delay;
  4257.                     MakeLowerCase(options);
  4258.                     BlindMovieCapture := false;
  4259.                     LG3BufferCapture := false;
  4260.                     TriggerFirstFrameOnly := true;
  4261.                     TimeStamp := false;
  4262.                     UseExistingStack := false;
  4263.                     if pos('blind', options) <> 0 then
  4264.                         BlindMovieCapture := true;
  4265.                     if (pos('buffer', options) <> 0) then
  4266.                         LG3BufferCapture := true;
  4267.                     if (pos('stamp', options) <> 0) then
  4268.                             TimeStamp := true;
  4269.                     if (pos('trigger', options) <> 0) and (pos('first', options) <> 0) then begin
  4270.                         ExternalTrigger := true;
  4271.                         TriggerFirstFrameOnly := true;
  4272.                       end;
  4273.                     if (pos('trigger', options) <> 0) and (pos('each', options) <> 0) then begin
  4274.                         ExternalTrigger := true;
  4275.                         TriggerFirstFrameOnly := false;
  4276.                       end;
  4277.                     if (pos('existing', options) <> 0) then
  4278.                             UseExistingStack := true;
  4279.                     MakeMovie(ShowDialog);
  4280.                 end;
  4281.     end;
  4282.  
  4283.  
  4284.     procedure DoAnalyzeParticles; {[(Options:string)]}
  4285.         var
  4286.             options: str255;
  4287.             hasOptions, okay: boolean;
  4288.     begin
  4289.         GetToken;
  4290.         hasOptions := token = LeftParen;
  4291.         PutTokenBack;
  4292.         if hasOptions then begin
  4293.             GetArguments(options);
  4294.             MakeLowerCase(options);
  4295.             if pos('dialog', options) <> 0 then begin
  4296.                 okay := DoAPDialog;
  4297.                 if okay then
  4298.                     AnalyzeParticles;
  4299.                 exit(DoAnalyzeParticles);
  4300.             end;
  4301.             LabelParticles := false;
  4302.             OutlineParticles := false;
  4303.             IgnoreParticlesTouchingEdge := false;
  4304.             IncludeHoles := false;
  4305.             APReset := false;
  4306.             if pos('label', options) <> 0 then
  4307.                 LabelParticles := true;
  4308.             if pos('outline', options) <> 0 then
  4309.                 OutlineParticles := true;
  4310.             if pos('ignore', options) <> 0 then
  4311.                 IgnoreParticlesTouchingEdge := true;
  4312.             if pos('include', options) <> 0 then
  4313.                 IncludeHoles := true;
  4314.             if pos('reset', options) <> 0 then
  4315.                 APReset := true;
  4316.         end;
  4317.         AnalyzeParticles;
  4318.     end;
  4319.  
  4320.  
  4321.   procedure SetProjection;
  4322.     var
  4323.       v: extended;
  4324.       s: str255;
  4325.   begin
  4326.     GetLeftParen;
  4327.     s := GetString;
  4328.         MakeLowerCase(s);
  4329.     if pos('x-axis', s) <> 0 then
  4330.       AxisOfRotation := XAxis
  4331.     else if pos('y-axis', s) <> 0 then
  4332.       AxisOfRotation := YAxis
  4333.     else if pos('z-axis', s) <> 0 then
  4334.       AxisOfRotation := ZAxis
  4335.     else if pos('nearest', s) <> 0 then
  4336.       ProjectionMethod := NearestPoint
  4337.     else if pos('brightest', s) <> 0 then
  4338.       ProjectionMethod := BrightestPoint
  4339.     else if pos('mean', s) <> 0 then
  4340.       ProjectionMethod := MeanValue
  4341.     else begin
  4342.         GetComma;
  4343.         if pos('save', s) <> 0 then
  4344.           SaveProjections := GetBoolean
  4345.         else if pos('minimize', s) <> 0 then
  4346.           MinProjSize := GetBoolean
  4347.         else begin
  4348.             v := GetExpression;
  4349.             if pos('initial', s) <> 0 then
  4350.               InitAngle := round(v)
  4351.             else if pos('total', s) <> 0 then
  4352.               TotalAngle := round(v)
  4353.             else if pos('increment', s) <> 0 then
  4354.               AngleInc := round(v)
  4355.             else if pos('opacity', s) <> 0 then
  4356.               Opacity := round(v)
  4357.             else if pos('surface', s) <> 0 then
  4358.               DepthCueSurf := 100 - round(v)
  4359.             else if pos('interior', s) <> 0 then
  4360.               DepthCueInt := 100 - round(v)
  4361.             else
  4362.               MacroError('String not recognized:');
  4363.           end;
  4364.       end;
  4365.     GetRightParen;
  4366.         RoutinesCalled := RoutinesCalled + [SetProjectionC];
  4367.   end;
  4368.   
  4369.   
  4370.     procedure DoGetHistogram;
  4371.         var
  4372.             Left, Top, Width, Height: integer;
  4373.             SaveRoiRect: rect;
  4374.     begin
  4375.         GetLeftParen;
  4376.         left := GetInteger;
  4377.         GetComma;
  4378.         top := GetInteger;
  4379.         GetComma;
  4380.         width := GetInteger;
  4381.         if width < 1 then
  4382.             width := 1;
  4383.         GetComma;
  4384.         height := GetInteger;
  4385.         if height < 1 then
  4386.             height := 1;
  4387.         GetRightParen;
  4388.         if token <> DoneT then
  4389.             with Info^ do begin
  4390.                     SaveRoiRect := RoiRect;
  4391.                     SetRect(RoiRect, left, top, left + width, top + height);
  4392.                     GetRectHistogram;
  4393.                     RoiRect := SaveRoiRect;
  4394.                 end;
  4395.     end;
  4396.  
  4397.  
  4398.     procedure doFFTMacro; {(Options:string)}
  4399.         var
  4400.             options: str255;
  4401.     begin
  4402.         GetLeftParen;
  4403.         Options := GetString;
  4404.         GetRightParen;
  4405.         if (Token <> DoneT) then begin
  4406.                 MakeLowerCase(options);
  4407.                 if pos('foreward', options) <> 0 then
  4408.                     doFFT(ForewardFFT)
  4409.                 else if pos('inverse', options) <> 0 then begin
  4410.                     if pos('without', options) <> 0 then
  4411.                         doFFT(InverseFFT)
  4412.                     else if pos('filter', options) <> 0 then
  4413.                         doFFT(InverseFFTWithFilter)
  4414.                     else doFFT(InverseFFTWithMask)
  4415.                 end else if pos('display', options) <> 0 then
  4416.                     RedisplayPowerSpectrum
  4417.                 else if pos('swap', options) <> 0 then
  4418.                     doSwapQuadrants
  4419.                 else
  4420.                     MacroError('Unrecognized argument');
  4421.             end;
  4422.     end;
  4423.  
  4424.  
  4425.       procedure ExecuteCommand;
  4426.         var
  4427.             AutoSelectAll: boolean;
  4428.             t: FateTable;  {Needed for MakeSkeleton}
  4429.             okay: boolean;
  4430.             theEvent: EventRecord;
  4431.     begin
  4432.         if Info = NoInfo then
  4433.             if not (MacroCommand in LegalWithoutImage) then begin
  4434.                     MacroError('No image window active');
  4435.                     exit(ExecuteCommand);
  4436.                 end;
  4437.         if DoOption then begin
  4438.                 OptionKeyWasDown := true;
  4439.                 DoOption := false;
  4440.             end;
  4441.         if OpPending then
  4442.             if not (MacroCommand in [CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC, SetOptionC, PasteLiveC, GetRoiC, RequiresC, UndoC]) then begin
  4443.                     KillRoi; {Terminate any pending paste operation.}
  4444.                     RestoreRoi;
  4445.                 end;
  4446.         case MacroCommand of
  4447.             RotateRC, RotateLC: 
  4448.                 DoRotate(MacroCommand);
  4449.             FlipVC: 
  4450.                 FlipOrRotate(FlipVertical);
  4451.             FlipHC: 
  4452.                 FlipOrRotate(FlipHorizontal);
  4453.             CopyC:  begin
  4454.                     FindWhatToCopy;
  4455.                     if WhatToCopy = NothingToCopy then
  4456.                         MacroError('Copy failed')
  4457.                     else
  4458.                         DoCopy;
  4459.                 end;
  4460.             SelectC:
  4461.                 if CurrentWindow = TextKind then
  4462.                     SelectAllText
  4463.                 else begin
  4464.                     StopDigitizing;
  4465.                     SelectAll(true);
  4466.                 end;
  4467.             PasteC: 
  4468.                 DoPaste;
  4469.             ClearC, FillC, InvertC, FrameC: 
  4470.                 with info^ do begin
  4471.                         AutoSelectAll := not RoiShowing;
  4472.                         if AutoSelectAll then
  4473.                             SelectAll(true);
  4474.                         case MacroCommand of
  4475.                             ClearC: 
  4476.                                 DoOperation(EraseOp);
  4477.                             FillC: 
  4478.                                 DoOperation(PaintOp);
  4479.                             InvertC: 
  4480.                                 DoOperation(InvertOp);
  4481.                             FrameC: 
  4482.                                 DoOperation(FrameOp);
  4483.                         end;
  4484.                         UpdateScreen(RoiRect);
  4485.                         if AutoSelectAll then
  4486.                             KillRoi;
  4487.                     end;
  4488.             KillC: 
  4489.                 KillRoi;
  4490.             RestoreC: 
  4491.                 if NoInfo^.RoiType <> NoRoi then
  4492.                     RestoreRoi;
  4493.             AnalyzeC: 
  4494.                 DoAnalyzeParticles;
  4495.             ConvolveC: 
  4496.                 DoConvolve;
  4497.             NextC: 
  4498.                 GetNextWindow;
  4499.             MarkC: 
  4500.                 MarkSelection(mCount);
  4501.             MeasureC:  begin
  4502.                     Measure;
  4503.                     InitCursor;
  4504.                 end;
  4505.             MakeBinC: 
  4506.                 MakeBinary;
  4507.             DitherC: 
  4508.                 Filter(Dither, 0, t);
  4509.             SmoothC: 
  4510.                 if OptionKeyWasDown then
  4511.                     Filter(UnweightedAvg, 0, t)
  4512.                 else
  4513.                     Filter(WeightedAvg, 0, t);
  4514.             SharpenC: 
  4515.                 Filter(fsharpen, 0, t);
  4516.             ShadowC: 
  4517.                 DoShadow;
  4518.             TraceC: 
  4519.                 Filter(EdgeDetect, 0, t);
  4520.             ReduceC: 
  4521.                 Filter(ReduceNoise, 0, t);
  4522.             RedirectC: 
  4523.                 RedirectSampling := GetBooleanArg;
  4524.             ThresholdC: 
  4525.                 SetThreshold;
  4526.             AutoThresholdC: 
  4527.                 AutoThreshold;
  4528.             ResetgmC: 
  4529.                 ResetGrayMap;
  4530.             WaitC: 
  4531.                 DoWait;
  4532.             ResetmC: 
  4533.                 ResetCounter;
  4534.             SetSliceC: 
  4535.                 SetDensitySlice;
  4536.             UndoC: 
  4537.                 DoUndo;
  4538.             SetForeC, SetBackC: 
  4539.                 SetColor;
  4540.             HistoC:  begin
  4541.                     DoHistogram;
  4542.                     DrawHistogram;
  4543.                 end;
  4544.             EnhanceC: 
  4545.                 EnhanceContrast;
  4546.             EqualizeC: 
  4547.                 EqualizeHistogram;
  4548.             ErodeC:  begin
  4549.                     BinaryIterations := 1;
  4550.                     DoErosion;
  4551.                 end;
  4552.             DilateC:  begin
  4553.                     BinaryIterations := 1;
  4554.                     DoDilation;
  4555.                 end;
  4556.             OutlineC: 
  4557.                 filter(OutlineFilter, 0, t);
  4558.             ThinC: 
  4559.                 MakeSkeleton;
  4560.             AddConstC, MulConstC: 
  4561.                 DoConstantArithmetic;
  4562.             RevertC: 
  4563.                 DoRevert;
  4564.             BeepC: 
  4565.                 Beep;
  4566.             NopC: 
  4567.                 ;
  4568.             MakeC, MakeOvalC: 
  4569.                 MakeRoi;
  4570.             MoveC: 
  4571.                 MoveRoi;
  4572.             InsetC: 
  4573.                 InsetRoi;
  4574.             MoveToC: 
  4575.                 DoMoveTo;
  4576.             DrawTextC, WriteC, WritelnC, ShowMsgC: 
  4577.                 OutputText;
  4578.             SetFontC: 
  4579.                 SetFont;
  4580.             SetFontSizeC: 
  4581.                 SetFontSize;
  4582.             SetTextC: 
  4583.                 SetText;
  4584.             DrawNumC: 
  4585.                 DrawNumber;
  4586.             ExitC: 
  4587.                 token := DoneT;
  4588.             GetPicSizeC: 
  4589.                 GetPicSize;
  4590.             PutMsgC: 
  4591.                 DoPutMessage;
  4592.             GetRoiC: 
  4593.                 GetRoi;
  4594.             MakeNewC: 
  4595.                 DoMakeNewWindow;
  4596.             DrawScaleC: 
  4597.                 if info^.RoiShowing then begin
  4598.                         DrawScale;
  4599.                         UpdatePicWindow
  4600.                     end
  4601.                 else
  4602.                     MacroError('No Selection');
  4603.             SetPaletteC: 
  4604.                 DoSetPalette;
  4605.             OpenC, ImportC: 
  4606.                 DoOpenImage;
  4607.             SetImportC: 
  4608.                 SetImportAttributes;
  4609.             SetMinMaxC: 
  4610.                 SetImportMinMax;
  4611.             SetCustomC: 
  4612.                 SetCustomImport;
  4613.             SelectPicC, ChoosePicC: 
  4614.                 SelectPic;
  4615.             SetPicNameC: 
  4616.                 SetPicName;
  4617.             ApplyLutC: 
  4618.                 ApplyLookupTable;
  4619.             SetSizeC: 
  4620.                 SetNewSize;
  4621.             SaveC: 
  4622.                 DoSave;
  4623.             SaveAllC: 
  4624.                 SaveAll;
  4625.             SaveAsC: 
  4626.                 DoSaveAs;
  4627.             CopyResultsC: 
  4628.                 DoCopyResults;
  4629.             CloseC, DisposeC: 
  4630.                 CloseWindow;
  4631.             DisposeAllC: 
  4632.                 DisposeAll;
  4633.             DupC: 
  4634.                 DoDuplicate;
  4635.             GetInfoC: 
  4636.                 GetInfo;
  4637.             PrintC: 
  4638.                 DoPrint;
  4639.             LineToC: 
  4640.                 DoLineTo;
  4641.             GetLineC: 
  4642.                 DoGetLine;
  4643.             ShowPasteC: 
  4644.                 if PasteControl = nil then
  4645.                     ShowPasteControl
  4646.                 else
  4647.                     BringToFront(PasteControl);
  4648.             ChannelC: 
  4649.                 SetChannel;
  4650.             ColumnC, PlotProfileC:  begin
  4651.                     PlotDensityProfile;
  4652.                     if PlotWindow <> nil then
  4653.                         UpdatePlotWindow;
  4654.                 end;
  4655.             ScaleC, ScaleSelectionC: 
  4656.                 DoScaleAndRotate;
  4657.             SetOptionC: 
  4658.                 DoOption := true;
  4659.             SetLabelsC: 
  4660.                 DrawPlotLabels := GetBooleanArg;
  4661.             SetPlotScaleC: 
  4662.                 SetPlotScale;
  4663.             SetDimC: 
  4664.                 SetPlotDimensions;
  4665.             GetResultsC: 
  4666.                 GetResults;
  4667.             CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC: 
  4668.                 DoPasteOperation;
  4669.             ScaleMathC: 
  4670.                 ScaleArithmetic := GetBooleanArg;
  4671.             InvertYC: 
  4672.                 InvertYCoordinates := GetBooleanArg;
  4673.             SetWidthC: 
  4674.                 SetWidth;
  4675.             ShowResultsC:  begin
  4676.                     ShowResults;
  4677.                     UpdateList
  4678.                 end;
  4679.             StartC: 
  4680.                 StartDigitizing;
  4681.             StopC: 
  4682.                 StopDigitizing;
  4683.             CaptureC: 
  4684.                 CaptureOneFrame;
  4685.             GetRowC, PutRowC, GetColumnC, PutColumnC: 
  4686.                 GetOrPutLineOrColumn;
  4687.             PlotXYZC: 
  4688.                 PlotXYZ;
  4689.             IncludeC: 
  4690.                 IncludeHoles := GetBooleanArg;
  4691.             AutoC: 
  4692.                 WandAutoMeasure := GetBooleanArg;
  4693.             LabelC: 
  4694.                 LabelParticles := GetBooleanArg;
  4695.             OutlineParticlesC: 
  4696.                 OutlineParticles := GetBooleanArg;
  4697.             IgnoreC: 
  4698.                 IgnoreParticlesTouchingEdge := GetBooleanArg;
  4699.             AdjustC: 
  4700.                 WandAdjustAreas := GetBooleanArg;
  4701.             SetParticleSizeC: 
  4702.                 SetParticleSize;
  4703.             SetPrecisionC: 
  4704.                 SetPrecision;
  4705.             PutPixelC: 
  4706.                 DoPutPixel;
  4707.             ScalingOptionsC: 
  4708.                 SetScaling;
  4709.             SetExportC: 
  4710.                 SetExportMode;
  4711.             ExportC: 
  4712.                 DoExport;
  4713.             ChangeC: 
  4714.                 DoChangeValues;
  4715.             UpdateResultsC:  begin
  4716.                     ShowInfo;
  4717.                     DeleteLines(mCount, mCount);
  4718.                     AppendResults;
  4719.                 end;
  4720.             TileC: 
  4721.                 TileImages;
  4722.             SetMajorC, SetMinorC, SetUser1C, SetUser2C: 
  4723.                 SetLabel;
  4724.             GetMouseC: 
  4725.                 DoGetMouse;
  4726.             SelectSliceC, ChooseSliceC, AddSliceC, DeleteSliceC, ResliceC:  begin
  4727.                     if info^.StackInfo = nil then
  4728.                         MacroError('No stack');
  4729.                     if token <> DoneT then
  4730.                         case MacroCommand of
  4731.                             SelectSliceC, ChooseSliceC: 
  4732.                                 DoSelectSlice;
  4733.                             AddSliceC: 
  4734.                                 okay := AddSlice(true);
  4735.                             DeleteSliceC: 
  4736.                                 DeleteSlice;
  4737.                             ResliceC: 
  4738.                                 Reslice;
  4739.                         end;
  4740.                 end;
  4741.             MakeStackC: 
  4742.                 MakeNewStack;
  4743.             AverageFramesC: 
  4744.                 DoAverageFrames;
  4745.             TriggerC: 
  4746.                 WaitForTrigger;
  4747.             MakeLineC: 
  4748.                 MakeLineRoi;
  4749.             GetTimeC: 
  4750.                 DoGetTime;
  4751.             SetScaleC: 
  4752.                 DoSetScale;
  4753.             SaveStateC: 
  4754.                 SaveState;
  4755.             RestoreStateC: 
  4756.                 RestoreState;
  4757.             SetCounterC: 
  4758.                 SetCounter;
  4759.             UpdateLutC: 
  4760.                 DoUpdateLUT;
  4761.             SetCountC: 
  4762.                 SetErosionDilationCount;
  4763.             PropagateLutC: 
  4764.                 DoPropagate(1);
  4765.             PropagateSpatialC: 
  4766.                 DoPropagate(2);
  4767.             PropagateDensityC: 
  4768.                 DoPropagate(3);
  4769.             SetSpacingC: 
  4770.                 SetSliceSpacing;
  4771.             RequiresC: 
  4772.                 CheckVersion;
  4773.             SetOptionsC: 
  4774.                 SetOptions;
  4775.             SubtractBackgroundC: 
  4776.                 SubtractBackground;
  4777.             MoveWindowC: 
  4778.                 MoveCurrentWindow;
  4779.             UserCodeC: 
  4780.                 DoUserCode;
  4781.             InvertLutC:  begin
  4782.                     InvertPalette;
  4783.                     UpdateLUT;
  4784.                 end;
  4785.             OpenSerialC: 
  4786.                 OpenSerial;
  4787.             PutSerialC: 
  4788.                 PutSerial;
  4789.             SetCursorC: 
  4790.                 DoSetCursor;
  4791.             SetVideoC: 
  4792.                 SetVideoOptions;
  4793.             AcquireC: 
  4794.                 DoAcquire;
  4795.             CallFilterC: 
  4796.                 CallFilterPlugin;
  4797.             PhotoModeC: 
  4798.                 DoPhotoMode;
  4799.             RGBToIndexedC: 
  4800.                 RGBToIndexed;
  4801.             SurfacePlotC: 
  4802.                 PlotSurface;
  4803.             SelectWindowC: 
  4804.                 DoSelectWindow;
  4805.             NewTextWindowC: 
  4806.                 DoNewTextWindow;
  4807.             CaptureColorC: 
  4808.                 CaptureColor;
  4809.             GetThresholdC: 
  4810.                 GetThreshold;
  4811.             AverageSlicesC: 
  4812.                 AverageSlices;
  4813.             SortPaletteC: 
  4814.                 SortPalette;
  4815.             ProjectC: 
  4816.                 DoProject;
  4817.             ScaleConvolutionsC: 
  4818.                 ScaleConvolutions := GetBooleanArg;
  4819.             ImageMathC: 
  4820.                 ImageMath;
  4821.             PasteLiveC: 
  4822.                 PasteLive;
  4823.             GetPlotDataC: 
  4824.                 GetPlotData;
  4825.             DeleteC: 
  4826.                 DoDelete;
  4827.             GetScaleC: 
  4828.                 GetScale;
  4829.             AutoOutlineC: 
  4830.                 DoAutoOutline;
  4831.             FilterC: 
  4832.                 DoFilter;
  4833.             SetSaveAsC:
  4834.                 SetSaveAsMode;
  4835.             CalibrateC:
  4836.                 DoCalibrate;
  4837.             CallExportC:
  4838.                 CallExportPlugin;
  4839.             IndexedToRGBC:
  4840.                 ConvertEightBitColorToRGB;
  4841.             MakeMovieC:
  4842.                 DoMakeMovie;
  4843.        SetProjectionC:
  4844.           SetProjection;
  4845.        GetHistogramC:
  4846.               DoGetHistogram;
  4847.               fftC:
  4848.           doFFTMacro;
  4849.         end; {case}
  4850.         OptionKeyWasDown := false;
  4851.         if not macro then begin
  4852.                 Token := DoneT;
  4853.                 KillRoi;
  4854.             end;
  4855.         if TickCount > MacroTicks then begin
  4856.                 if EventAvail(everyEvent, theEvent) then; {Allows background tasks to run}
  4857.                 if CommandPeriod then begin
  4858.                         Token := DoneT;
  4859.                         KillRoi;
  4860.                     end;
  4861.                 MacroTicks := TickCount + 15;
  4862.             end;
  4863.     end;
  4864.  
  4865.  
  4866.     procedure DoCompoundStatement;
  4867.     begin
  4868.         if token <> BeginT then
  4869.             MacroError('"begin" expected');
  4870.         GetToken;
  4871.         while (token <> endT) and (token <> DoneT) do begin
  4872.                 DoStatement;
  4873.                 GetToken;
  4874.                 if Token = SemiColon then
  4875.                     GetToken
  4876.                 else if token <> EndT then
  4877.                     MacroError(EndExpected);
  4878.             end;
  4879.     end;
  4880.  
  4881.  
  4882.     procedure SkipCompoundStatement;
  4883.         var
  4884.             count: integer;
  4885.     begin
  4886.         count := 1;
  4887.         repeat
  4888.             GetToken;
  4889.             case token of
  4890.                 beginT: 
  4891.                     count := count + 1;
  4892.                 endT: 
  4893.                     count := count - 1;
  4894.                 DoneT:  begin
  4895.                         MacroError('"end" expected');
  4896.                         exit(SkipCompoundStatement);
  4897.                     end;
  4898.                 otherwise
  4899.             end; {case}
  4900.         until count = 0;
  4901.     end;
  4902.  
  4903.  
  4904.     procedure DoDeclarations;
  4905.     begin
  4906.         if token = SemiColon then
  4907.             GetToken;
  4908.         if token = VarT then begin
  4909.                 GetToken;
  4910.                 while ((token = Identifier) or (token = variable) or (token = StringVariable)) and (Token <> DoneT) do
  4911.                     DoDeclaration;
  4912.             end;
  4913.     end;
  4914.  
  4915.  
  4916.     procedure DoFor;
  4917.         var
  4918.             SavePC, StackLoc: integer;
  4919.             StartValue, EndValue, i: LongInt;
  4920.     begin
  4921.         StackLoc := GetVar;
  4922.         GetToken;
  4923.         if token <> AssignOp then begin
  4924.                 MacroError('":=" expected');
  4925.                 exit(DoFor);
  4926.             end;
  4927.         StartValue := GetInteger;
  4928.         if token = DoneT then
  4929.             exit(DoFor);
  4930.         GetToken;
  4931.         if token <> ToT then begin
  4932.                 MacroError('"to" expected');
  4933.                 exit(DoFor);
  4934.             end;
  4935.         EndValue := GetInteger;
  4936.         if token = DoneT then
  4937.             exit(DoFor);
  4938.         GetToken;
  4939.         if token <> DoT then begin
  4940.                 MacroError(DoExpected);
  4941.                 exit(DoFor);
  4942.             end;
  4943.         SavePC := pc;
  4944.         if StartValue > EndValue then begin
  4945.                 GetToken;
  4946.                 SkipStatement
  4947.             end
  4948.         else
  4949.             for i := StartValue to EndValue do
  4950.                 with MacrosP^ do begin
  4951.                         Stack[StackLoc].value := i;
  4952.                         pc := SavePC;
  4953.                         GetToken;
  4954.                         DoStatement;
  4955.                         LoopCounter := LoopCounter + 1;
  4956.                         if LoopCounter >= MaxLoopCount then begin
  4957.                             if CommandPeriod then
  4958.                                 token := DoneT;
  4959.                             LoopCounter := 0;
  4960.                         end;
  4961.                         if Token = DoneT then
  4962.                             leave;
  4963.                         if Digitizing then
  4964.                             DoCapture;
  4965.                     end;
  4966.     end;
  4967.  
  4968.  
  4969.     procedure SkipFor;
  4970.     begin
  4971.         GetToken;
  4972.         SkipPartialStatement;
  4973.         GetToken;
  4974.         if token <> doT then
  4975.             MacroError(DoExpected);
  4976.         GetToken;
  4977.         SkipStatement
  4978.     end;
  4979.  
  4980.  
  4981.     procedure DoAssignment;
  4982.         var
  4983.             SaveStackLoc: integer;
  4984.     begin
  4985.         SaveStackLoc := TokenStackLoc;
  4986.         GetToken;
  4987.         if token <> AssignOp then begin
  4988.                 MacroError('":=" expected');
  4989.                 exit(DoAssignment);
  4990.             end;
  4991.         MacrosP^.stack[SaveStackLoc].value := GetBooleanExpression;
  4992.     end;
  4993.  
  4994.  
  4995.     procedure DoStringAssignment;
  4996.         var
  4997.             SaveStackLoc: integer;
  4998.             str: Str255;
  4999.     begin
  5000.         SaveStackLoc := TokenStackLoc;
  5001.         GetToken;
  5002.         if token <> AssignOp then begin
  5003.                 MacroError('":=" expected');
  5004.                 exit(DoStringAssignment);
  5005.             end;
  5006.         str := GetString;
  5007.         if token <> DoneT then
  5008.             with MacrosP^.stack[SaveStackLoc] do
  5009.                 if StringH <> nil then
  5010.                     StringH^^ := str;
  5011.     end;
  5012.  
  5013.  
  5014.     procedure SkipPartialStatement;
  5015.         var
  5016.             done: Boolean;
  5017.     begin
  5018.         done := token = DoneT;
  5019.         while not done do begin
  5020.                 case token of
  5021.                     ThenT, DoT, SemiColon, EndT, ElseT, UntilT:  begin
  5022.                             PutTokenBack;
  5023.                             done := true;
  5024.                         end;
  5025.                     DoneT, BeginT, ForT, IfT, WhileT, RepeatT:  begin
  5026.                             MacroError('end of statement expected');
  5027.                             done := true;
  5028.                         end;
  5029.                     otherwise
  5030.                         GetToken;
  5031.                 end;
  5032.             end;
  5033.     end;
  5034.  
  5035.  
  5036.     procedure DoIf;
  5037.         var
  5038.             isTrue: boolean;
  5039.     begin
  5040.         isTrue := GetBoolean;
  5041.         GetToken;
  5042.         if token <> ThenT then
  5043.             MacroError(ThenExpected);
  5044.         if isTrue then begin
  5045.                 GetToken;
  5046.                 DoStatement
  5047.             end
  5048.         else begin
  5049.                 GetToken;
  5050.                 SkipStatement;
  5051.             end;
  5052.         GetToken;
  5053.         if token = elseT then begin
  5054.                 if isTrue then begin
  5055.                         GetToken;
  5056.                         SkipStatement
  5057.                     end
  5058.                 else begin
  5059.                         GetToken;
  5060.                         DoStatement;
  5061.                     end;
  5062.             end
  5063.         else
  5064.             PutTokenBack;
  5065.     end;
  5066.  
  5067.  
  5068.     procedure SkipIf;
  5069.     begin
  5070.         GetToken;
  5071.         SkipPartialStatement;
  5072.         GetToken;
  5073.         if token <> thenT then
  5074.             MacroError(ThenExpected);
  5075.         GetToken;
  5076.         SkipStatement;
  5077.         GetToken;
  5078.         if token <> elseT then
  5079.             PutTokenBack
  5080.         else begin
  5081.                 GetToken;
  5082.                 SkipStatement
  5083.             end
  5084.     end;
  5085.  
  5086.  
  5087.     procedure DoWhile;
  5088.         var
  5089.             isTrue: boolean;
  5090.             SavePC: integer;
  5091.     begin
  5092.         SavePC := pc;
  5093.         repeat
  5094.             pc := SavePC;
  5095.             isTrue := GetBoolean;
  5096.             GetToken;
  5097.             if token <> doT then
  5098.                 MacroError(DoExpected);
  5099.             if isTrue then begin
  5100.                     GetToken;
  5101.                     DoStatement
  5102.                 end
  5103.             else begin
  5104.                     GetToken;
  5105.                     SkipStatement;
  5106.                 end;
  5107.             if Digitizing then
  5108.                 DoCapture;
  5109.             LoopCounter := LoopCounter + 1;
  5110.             if LoopCounter >= MaxLoopCount then begin
  5111.                 if CommandPeriod then
  5112.                     token := DoneT;
  5113.                 LoopCounter := 0;
  5114.             end;
  5115.         until not isTrue or (Token = DoneT);
  5116.     end;
  5117.  
  5118.  
  5119.     procedure SkipWhile;
  5120.     begin
  5121.         GetToken;
  5122.         SkipPartialStatement;
  5123.         GetToken;
  5124.         if token <> doT then
  5125.             MacroError(DoExpected);
  5126.         GetToken;
  5127.         SkipStatement
  5128.     end;
  5129.  
  5130.  
  5131.     procedure DoRepeat;
  5132.         var
  5133.             isTrue: boolean;
  5134.             SavePC: integer;
  5135.     begin
  5136.         SavePC := pc;
  5137.         isTrue := true;
  5138.         repeat
  5139.             pc := SavePC;
  5140.             GetToken;
  5141.             while (token <> untilT) and (token <> DoneT) do begin
  5142.                     DoStatement;
  5143.                     GetToken;
  5144.                     if Token = SemiColon then
  5145.                         GetToken;
  5146.                     LoopCounter := LoopCounter + 1;
  5147.                     if LoopCounter >= MaxLoopCount then begin
  5148.                         if CommandPeriod then
  5149.                             token := DoneT;
  5150.                         LoopCounter := 0;
  5151.                     end;
  5152.                 end;
  5153.             if token <> untilT then
  5154.                 MacroError(UntilExpected);
  5155.             isTrue := GetBoolean;
  5156.             if Digitizing then
  5157.                 DoCapture;
  5158.         until isTrue or (Token = DoneT);
  5159.     end;
  5160.  
  5161.  
  5162.     procedure SkipRepeat;
  5163.     begin
  5164.         GetToken;
  5165.         while (token <> untilT) and (token <> DoneT) do begin
  5166.                 SkipStatement;
  5167.                 GetToken;
  5168.                 if token = SemiColon then
  5169.                     GetToken
  5170.                 else if token <> UntilT then
  5171.                     MacroError(UntilExpected);
  5172.             end;
  5173.         GetToken;
  5174.         SkipPartialStatement;
  5175.     end;
  5176.  
  5177.  
  5178.     procedure DoArrayAssignment;
  5179.         var
  5180.             SaveArrayType: ArrayType;
  5181.             index, LutValue, PixelValue, RegisterValue: LongInt;
  5182.             SyncChannel: integer;
  5183.     begin
  5184.         SaveArrayType := ArrayType(MacroCommand);
  5185.         GetToken;
  5186.         if token <> LeftBracket then
  5187.             MacroError('"[" expected');
  5188.         Index := GetInteger;
  5189.         GetToken;
  5190.         if token <> RightBracket then
  5191.             MacroError('"]" expected');
  5192.         GetToken;
  5193.         if token <> AssignOp then
  5194.             MacroError('":=" expected');
  5195.  
  5196.         if SaveArrayType = BufferA then begin
  5197.                 CheckIndex(index, 0, MaxLine - 1);
  5198.                 PixelValue := GetInteger;
  5199.                 RangeCheck(PixelValue);
  5200.                 if token <> DoneT then
  5201.                     MacrosP^.aLine[index] := PixelValue;
  5202.                 exit(DoArrayAssignment);
  5203.             end;
  5204.  
  5205.         if SaveArrayType in [RedLutA, BlueLutA, GreenLutA] then begin
  5206.                 RangeCheck(index);
  5207.                 LutValue := GetInteger;
  5208.                 RangeCheck(LutValue);
  5209.                 if token <> DoneT then
  5210.                     with info^.cTable[index].rgb do
  5211.                         case SaveArrayType of
  5212.                             RedLutA: 
  5213.                                 red := bsl(LutValue, 8);
  5214.                             GreenLutA: 
  5215.                                 green := bsl(LutValue, 8);
  5216.                             BlueLutA: 
  5217.                                 blue := bsl(LutValue, 8);
  5218.                         end;
  5219.                 exit(DoArrayAssignment);
  5220.             end;
  5221.  
  5222.         if SaveArrayType = ScionA then begin
  5223.                 if framegrabber <> ScionLG3 then
  5224.                     MacroError('No Scion LG-3');
  5225.                 if Token <> DoneT then
  5226.                     CheckIndex(index, 1, 4);
  5227.                 if Token = DoneT then
  5228.                     exit(DoArrayAssignment);
  5229.                 if index = 3 then
  5230.                     MacroError('DataIn is read-only');
  5231.                 RegisterValue := GetInteger;
  5232.                 if token <> DoneT then begin
  5233.                         if RegisterValue < 0 then
  5234.                             RegisterValue := 0;
  5235.                         if RegisterValue > 255 then
  5236.                             RegisterValue := 255;
  5237.                         case index of
  5238.                             1:  begin
  5239.                                     LG3DacA := RegisterValue;
  5240.                                     DacAReg^ := LG3DacA
  5241.                                 end;
  5242.                             2:  begin
  5243.                                     LG3DacB := RegisterValue;
  5244.                                     DacBReg^ := LG3DacB
  5245.                                 end;
  5246.                             4:  begin
  5247.                                     LG3DataOut := band(RegisterValue, $f);
  5248.                                     if SyncMode = SeparateSync then
  5249.                                         SyncChannel := 3
  5250.                                     else
  5251.                                         SyncChannel := VideoChannel;
  5252.                                     ChannelReg^ := bor(LG3DataOut, bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
  5253.                                 end;
  5254.                         end; {case}
  5255.                     end;
  5256.                 exit(DoArrayAssignment);
  5257.             end;
  5258.  
  5259.         if SaveArrayType = PlotDataA then begin
  5260.                 CheckIndex(index, 0, MaxLine - 1);
  5261.                 PlotData^[index] := GetExpression;
  5262.                 exit(DoArrayAssignment);
  5263.             end;
  5264.  
  5265.         CheckIndex(index, 1, MaxMeasurements);
  5266.         if token <> DoneT then
  5267.             case SaveArrayType of
  5268.                 rAreaA: 
  5269.                     mArea^[Index] := GetExpression;
  5270.                 rMeanA: 
  5271.                     mean^[Index] := GetExpression;
  5272.                 rStdDevA: 
  5273.                     sd^[Index] := GetExpression;
  5274.                 rXA: 
  5275.                     xcenter^[Index] := GetExpression;
  5276.                 rYA: 
  5277.                     ycenter^[Index] := GetExpression;
  5278.                 rLengthA: 
  5279.                     plength^[Index] := GetExpression;
  5280.                 rMinA: 
  5281.                     mMin^[Index] := GetExpression;
  5282.                 rMaxA: 
  5283.                     mMax^[Index] := GetExpression;
  5284.                 rMajorA: 
  5285.                     MajorAxis^[Index] := GetExpression;
  5286.                 rMinorA: 
  5287.                     MinorAxis^[Index] := GetExpression;
  5288.                 rAngleA: 
  5289.                     orientation^[Index] := GetExpression;
  5290.                 rUser1A: 
  5291.                     User1^[Index] := GetExpression;
  5292.                 rUser2A: 
  5293.                     User2^[Index] := GetExpression;
  5294.                 otherwise
  5295.                     MacroError('Read-only array');
  5296.             end; {case}
  5297.     end;
  5298.  
  5299.  
  5300.     procedure PushArguments (var nArgs: integer);
  5301.         var
  5302.             arg: array[1..MaxArgs] of extended;
  5303.             StringArg: array[1..MaxArgs] of boolean;
  5304.             i, nStringArgs: integer;
  5305.             TempName: SymbolType;
  5306.     begin
  5307.         nArgs := 0;
  5308.         nStringArgs := 0;
  5309.         GetToken;
  5310.         while token in [Variable, StringVariable, StringLiteral, NumericLiteral, TrueT, FalseT, FunctionT, StringFunctionT, ArrayT, comma, MinusOp, LeftParen] do begin
  5311.                 if token = comma then
  5312.                     GetToken;
  5313.                 if nArgs < MaxArgs then
  5314.                     nArgs := nArgs + 1
  5315.                 else
  5316.                     MacroError('Too many arguments');
  5317.                 if (token = StringVariable) or (token = StringLiteral) or (token = StringFunctionT) then begin
  5318.                         nStringArgs := nStringArgs + 1;
  5319.                         arg[nArgs] := 0.0;
  5320.                         StringArg[nArgs] := true;
  5321.                         if token = StringFunctionT then
  5322.                             TokenStr := DoStringFunction;
  5323.                     end
  5324.                 else begin
  5325.                         PutTokenBack;
  5326.                         arg[nArgs] := GetBooleanExpression;
  5327.                         StringArg[nArgs] := false;
  5328.                     end;
  5329.                 if nStringArgs > 1 then
  5330.                     MacroError('No more than one string argument allowed');
  5331.                 GetToken;
  5332.             end;
  5333.         if token <> RightParen then
  5334.             MacroError(RightParenExpected);
  5335.         for i := 1 to nArgs do begin
  5336.                 if TopOfStack < MaxMacroStackSize then
  5337.                     TopOfStack := TopOfStack + 1
  5338.                 else
  5339.                     MacroError(StackOverflow);
  5340.                 with MacrosP^.stack[TopOfStack] do begin
  5341.                         value := arg[i];
  5342.                         StringH := nil;
  5343.                         if StringArg[i] then begin
  5344.                                 vType := StringVar;
  5345.                                 StringsAllocated := true;
  5346.                                 StringH := str255H(NewHandle(SizeOf(str255)));
  5347.                                 if StringH = nil then begin
  5348.                                         MacroError('Out of memory');
  5349.                                         Token := DoneT
  5350.                                     end
  5351.                                 else
  5352.                                     StringH^^ := TokenStr;
  5353.                             end
  5354.                         else
  5355.                             vType := RealVar;
  5356.                         value := arg[i];
  5357.                     end;
  5358.             end;
  5359.     end;
  5360.  
  5361.  
  5362.     procedure DoProcedure;
  5363.         var
  5364.             SavePC, SavePCStart, NewPCStart, SaveStackLoc, nArgs, i: integer;
  5365.             SaveProcName, NewProcName: SymbolType;
  5366.             SaveStringsAllocated: boolean;
  5367.     begin
  5368.         NewPCStart := TokenLoc;
  5369.         NewProcName := TokenSymbol;
  5370.         SaveStackLoc := TopOfStack;
  5371.         SaveStringsAllocated := StringsAllocated;
  5372.         StringsAllocated := false;
  5373.         GetToken;
  5374.         if token = LeftParen then
  5375.             PushArguments(nArgs)
  5376.         else begin
  5377.                 nArgs := 0;
  5378.                 PutTokenBack;
  5379.             end;
  5380.         SavePCStart := PCStart;
  5381.         PCStart := NewPCStart;
  5382.         LineStartPC := NewPCStart;
  5383.         SaveProcName := MacroOrProcName;
  5384.         MacroOrProcName := NewProcName;
  5385.         SavePC := pc;
  5386.         pc := pcStart;
  5387.         if nArgs > 0 then begin
  5388.                 GetLeftParen;
  5389.                 i := 0;
  5390.                 GetToken;
  5391.                 while token in [Identifier, Variable, StringVariable, comma, colon, SemiColon, RealT, IntegerT, BooleanT, StringT] do begin
  5392.                         if (token = Identifier) or (token = Variable) or (token = StringVariable) then begin
  5393.                                 if i < nArgs then
  5394.                                     i := i + 1
  5395.                                 else
  5396.                                     MacroError('Too many formal arguments');
  5397.                                 MacrosP^.stack[SaveStackLoc + i].SymbolTableIndex := SymbolTableloc;
  5398.                             end;
  5399.                         GetToken;
  5400.                     end;
  5401.                 if Token = VarT then
  5402.                     MacroError('VAR parameters not supported');
  5403.                 if i < nArgs then
  5404.                     MacroError('Too few formal arguments');
  5405.                 if token <> RightParen then
  5406.                     MacroError(RightParenExpected);
  5407.             end;
  5408.         GetToken;
  5409.         if (token = LeftParen) and (nArgs = 0) then
  5410.             MacroError('Arguments not expected');
  5411.         DoDeclarations;
  5412.         DoCompoundStatement;
  5413.         pc := SavePC;
  5414.         if StringsAllocated then
  5415.             DeallocateStrings(SaveStackLoc + 1, TopOfStack);
  5416.         StringsAllocated := SaveStringsAllocated;
  5417.         TopOfStack := SaveStackLoc;
  5418.         pcStart := SavePCStart;
  5419.         MacroOrProcName := SaveProcName;
  5420.     end;
  5421.  
  5422.  
  5423.     procedure CannotBeginWithThis;
  5424.         var
  5425.             str: str255;
  5426.     begin
  5427.         str := '';
  5428.         ConvertTokenToString(token, str);
  5429.         MacroError(concat('Statement cannot begin with ', '"', str, '"'));
  5430.     end;
  5431.  
  5432.  
  5433.     procedure DoStatement;
  5434.     begin
  5435.         case token of
  5436.             BeginT: 
  5437.                 DoCompoundStatement;
  5438.             CommandT: 
  5439.                 ExecuteCommand;
  5440.             UserCommandT: 
  5441.                 DoUserToken;
  5442.             ForT: 
  5443.                 DoFor;
  5444.             IfT: 
  5445.                 DoIf;
  5446.             WhileT: 
  5447.                 DoWhile;
  5448.             RepeatT: 
  5449.                 DoRepeat;
  5450.             Identifier: 
  5451.                 MacroError('Undefined identifier');
  5452.             Variable: 
  5453.                 DoAssignment;
  5454.             StringVariable: 
  5455.                 DoStringAssignment;
  5456.             ArrayT: 
  5457.                 DoArrayAssignment;
  5458.             ProcedureT: 
  5459.                 DoProcedure;
  5460.             ElseT: 
  5461.                 MacroError('Statement expected');
  5462.             FunctionT, StringFunctionT, UserFuncT, UserStrFuncT: 
  5463.                 MacroError('Variable expected');
  5464.             SemiColon: 
  5465.                 PutTokenBack; {Null statement}
  5466.             otherwise
  5467.                 CannotBeginWithThis
  5468.         end;
  5469.     end;
  5470.  
  5471.  
  5472.     procedure SkipStatement;
  5473.     begin
  5474.         case token of
  5475.             BeginT: 
  5476.                 SkipCompoundStatement;
  5477.             ForT: 
  5478.                 SkipFor;
  5479.             IfT: 
  5480.                 SkipIf;
  5481.             WhileT: 
  5482.                 SkipWhile;
  5483.             RepeatT: 
  5484.                 SkipRepeat;
  5485.             CommandT, Variable, StringVariable, ArrayT, ProcedureT: 
  5486.                 SkipPartialStatement;
  5487.             DoneT: 
  5488.                 ; {Aborting the macro}
  5489.             SemiColon, EndT, ElseT, UntilT: 
  5490.                 PutTokenBack; {These tokens can follow a statement}
  5491.             otherwise
  5492.                 CannotBeginWithThis
  5493.         end;
  5494.     end;
  5495.  
  5496.  
  5497.  
  5498.     procedure RunMacro (nMacro: integer);
  5499.         var
  5500.             count: integer;
  5501.             str: str255;
  5502.             SaveInfo: InfoPtr;
  5503.     begin
  5504.         DefaultFileName := '';
  5505.         str := '';
  5506.         nSaves := 0;
  5507.         DefaultRefNum := 0;
  5508.         count := 0;
  5509.         pcStart := MacroStart[nMacro];
  5510.         pc := pcStart;
  5511.         SavePC := pcStart;
  5512.         LineStartPC := pcStart;
  5513.         token := NullT;
  5514.         macro := true;
  5515.         DoOption := false;
  5516.         SaveInfo := info;
  5517.         TopOfStack := nGlobals;
  5518.         MacroOrProcName := BlankSymbol;
  5519.         StringsAllocated := false;
  5520.         InPhotoMode := false;
  5521.         RoutinesCalled := [];
  5522.         MacroTicks := TickCount + 15;
  5523.         LoopCounter := 0;
  5524.         GetToken;
  5525.         DoDeclarations;
  5526.         DoCompoundStatement;
  5527.         if (info <> SaveInfo) and (info <> NoInfo) then
  5528.             SelectWindow(info^.wptr);
  5529.         with info^, RoiRect do begin
  5530.                 if ((right - left) <= 0) or ((bottom - top) <= 0) then
  5531.                     KillRoi;
  5532.             end;
  5533.         if info^.RoiShowing then
  5534.             if not (OpPending and (CurrentOp = PasteOp)) then begin
  5535.               KIllRoi;
  5536.               RestoreRoi;
  5537.             end;
  5538.         macro := false;
  5539.         if StringsAllocated then
  5540.             DeallocateStrings(nGlobals + 1, TopOfStack);
  5541.         if InPhotoMode then
  5542.             RestoreScreen;
  5543.     end;
  5544.  
  5545.  
  5546.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  5547.         const
  5548.             FunctionKey = 16;
  5549.         var
  5550.             i: integer;
  5551.     begin
  5552.         if (ord(ch) = 0) then
  5553.             exit(RunKeyMacro);
  5554.         if (ch >= 'A') and (ch <= 'Z') then
  5555.             ch := chr(ord(ch) + 32); {Convert to lower case}
  5556.         if ord(ch) = FunctionKey then
  5557.             case KeyCode of
  5558.                 122: 
  5559.                     ch := 'A';
  5560.                 120: 
  5561.                     ch := 'B';
  5562.                 99: 
  5563.                     ch := 'C';
  5564.                 118: 
  5565.                     ch := 'D';
  5566.                 96: 
  5567.                     ch := 'E';
  5568.                 97: 
  5569.                     ch := 'F';
  5570.                 98: 
  5571.                     ch := 'G';
  5572.                 100: 
  5573.                     ch := 'H';
  5574.                 101: 
  5575.                     ch := 'I';
  5576.                 109: 
  5577.                     ch := 'J';
  5578.                 103: 
  5579.                     ch := 'K';
  5580.                 111: 
  5581.                     ch := 'L';
  5582.                 105: 
  5583.                     ch := 'M';
  5584.                 107: 
  5585.                     ch := 'N';
  5586.                 113: 
  5587.                     ch := 'O';
  5588.                 otherwise
  5589.             end;
  5590.         for i := 1 to nMacros do
  5591.             if ch = MacroKey[i] then begin
  5592.                     RunMacro(i);
  5593.                     leave;
  5594.                 end;
  5595.     end;
  5596.  
  5597.  
  5598.  
  5599. end.